二叉树的基础操作

二叉树是基于递归思想建立的,所以我们对其做的操作大部分都得用递归思想。

我们队二叉树进行以下操作:

  • 二叉树的遍历
  • 根据遍历来创建二叉树
  • 二叉树的拷贝,销毁
  • 二叉树的节点个数,层数,深度,第K层节点数…
  • 二叉树查找元素,双亲,左右孩子

由于我们在根据遍历来创建二叉树时用了队列,所以我们要创建以下:
这里写图片描述

代码如下:(seqqueue的代码:https://blog.csdn.net/q496958148/article/details/80041078)
Makefile:

[test@localhost dtree]$ cat Makefile 
dtree:dtree.c seqqueue.c
    gcc $^ -o $@
.PHONY:clean
clean:
    rm -f dtree

dtree.h:

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include "seqqueue.h"

#define LINE1 printf("-----------------%s-----------------\n",__FUNCTION__);

typedef char DataType;

typedef struct BinaryTree{
    DataType data;
    struct BinaryTree* lchild;
    struct BinaryTree* rchild;
}BinaryTree;

BinaryTree* CreateNode(DataType value);
void DeleteNode(BinaryTree* node);

void treeInit(BinaryTree* head);

void treepreorder(BinaryTree* head);

void treeiorder(BinaryTree* head);

void treepostorder(BinaryTree* head);

void treelevelorder(BinaryTree* head,seqqueue* queue);

BinaryTree* preorderCreate(DataType buf[],size_t size);
BinaryTree* _preorderCreate(DataType buf[],int* index,size_t size);

void treeDestroy(BinaryTree* head);

BinaryTree* treeCpye(BinaryTree* head);

size_t treeleftSize(BinaryTree* head);

size_t treeNodeSize(BinaryTree* head);

size_t treeKLevelSize(BinaryTree* head,int K);

size_t treeHeight(BinaryTree* head);

BinaryTree* treeFind(BinaryTree* head,DataType value);

BinaryTree* treeLChild(BinaryTree* head);
BinaryTree* treeRChild(BinaryTree* head);

BinaryTree* treeParent(BinaryTree* head,BinaryTree* child);

dtree.c

#include "dtree.h"
#include "seqqueue.h"

//二叉树节点创建
BinaryTree* CreateNode(DataType value)
{
    //malloc出来的空间记得释放
    BinaryTree* new_node = (BinaryTree*)malloc(sizeof(BinaryTree));
    if(new_node == NULL)
    {
        perror("malloc");
        return NULL;
    }
    new_node->data = value;
    new_node->lchild = NULL;
    new_node->rchild = NULL;
    return new_node;
}

//节点的释放(删除)
void DeleteNode(BinaryTree* node)
{
    free(node);
    node = NULL;
}

//初始化
void treeInit(BinaryTree* head)
{
    if(head == NULL)
    {
        return;
    }
    head = NULL;
}

//先序遍历(递归思想)
void treepreorder(BinaryTree* head)
{
    if(head == NULL)
    {
        //printf("# ");
        return ;
    }
    printf("%c ",(head->data)-32);//将小写的字母转化尾大写的
    treepreorder(head->lchild);
    treepreorder(head->rchild);
}

//中序遍历(递归思想)
void treeiorder(BinaryTree* head)
{
    if(head == NULL)
    {
        return;
    }
    if(head->lchild != NULL)
    {
        treeiorder(head->lchild);
    }
    printf("%c ",(head->data)-32);
    if(head->rchild != NULL)
    {
        treeiorder(head->rchild);
    }
}

//后续遍历(递归思想)
void treepostorder(BinaryTree* head)
{
    if(head == NULL)
    {
        return;
    }
    if(head->lchild != NULL)
    {
        treepostorder(head->lchild);
    }
    if(head->rchild != NULL)
    {
        treepostorder(head->rchild);
    }
    printf("%c ",(head->data)-32);
}

//层序遍历(我借用了队列的思想,每次遍历一个根节点将其插入队列,并且出队列是将其的左右节点继续入队列)
void treelevelorder(BinaryTree* head,seqqueue* queue)
{
    if(head == NULL)
    {
        return;
    }
    seqqueuePush(queue,head);//创建一个保存节点的队列(并且将根节点插入队列头)
    while(1)
    {
        BinaryTree* tree = seqqueueGetTop(queue);//取得队列头
        printf("%c ",tree->data-32);//打印当前队列头
        if(tree->lchild != NULL)
        {
            seqqueuePush(queue,tree->lchild);//插入刚才打印的左子树
        }
        if(tree->rchild != NULL)
        {
            seqqueuePush(queue,tree->rchild);//插入刚才打印的右子树
        }
        seqqueuePop(queue);//出队列
        if(queue->size == 0)//当队列为空时,已经遍历完了
        {
            return;
        }
    }
}

//这个函数是专门处理递归中需要不断修改一个值的处理函数
BinaryTree* _preorderCreate(DataType buf[],int* index,size_t size)
{
    if(index == NULL)
    {
        return NULL;
    }
    if((*index) >= size)
    {
        return NULL;
    }
    if(buf[*index] == '#')
    {
       return NULL;
    }
    BinaryTree* new_node = CreateNode(buf[*index]);//每次还原一个点就将下标++
    ++(*index);
    new_node->lchild = _preorderCreate(buf,index,size);
    ++(*index);
    new_node->rchild = _preorderCreate(buf,index,size);
    return new_node;
}

//给出带有空子树信息的先序遍历数组,来还原二叉树
BinaryTree* preorderCreate(DataType buf[],size_t size)//参数:含有先序遍历的数组和数组的大小
{
    if(buf == NULL)
    {
        return NULL;
    }
    int index = 0;//数组的访问下标
    return  _preorderCreate(buf,&index,size);//为了线程安全这个概念,(定义全局变量在多线程中不安全,锁的应用)
}

//销毁二叉树(递归删除,我采用后续遍历)
void treeDestroy(BinaryTree* head)
{
    if(head == NULL)
    {
        return;
    }
    treeDestroy(head->lchild);
    treeDestroy(head->rchild);
    DeleteNode(head);
}

//二叉树拷贝(深拷贝和浅拷贝的思想,这采用的是深拷贝)
BinaryTree* treeCopy(BinaryTree* head)
{
   if(head == NULL)
   {
       return NULL;
   }
   BinaryTree* new_node = CreateNode(head->data);
   new_node->lchild = treeCopy(head->lchild);
   new_node->rchild = treeCopy(head->rchild);
   return new_node;
}

//求二叉树的总节点数(递归思想)
size_t treeNodeSize(BinaryTree* head)
{
    if(head == NULL)
    {
        return;
    }
    return 1 + treeNodeSize(head->lchild) + treeNodeSize(head->rchild);
}

//求叶子节点的个数(递归思想)
size_t treeleftSize(BinaryTree* head)
{
    if(head == NULL)
    {
        return 0;
    }
    if(head->lchild == NULL && head->rchild == NULL)
    {
        return 1;
    }
    return treeleftSize(head->lchild) + treeleftSize(head->rchild);
}

//求第K层的节点数(也是递归思想,根节点的K层,就是根节点子树的K-1层,一直到1层就是当前所求的层了)
size_t treeKLevelSize(BinaryTree* head,int K)
{
    if(head == NULL)
    {
        return 0;
    }
    if(K == 1)
    {
        return 1;
    }
    return treeKLevelSize(head->lchild,K-1) + treeKLevelSize(head->rchild,K-1);
}

//求树的高度
size_t treeHeight(BinaryTree* head)
{
    if(head == NULL)
    {
        return 0;
    }
    size_t lheight = treeHeight(head->lchild);
    size_t rheight = treeHeight(head->rchild);
    return 1+(lheight>rheight? lheight:rheight);
}

//查找元素在树中的节点
BinaryTree* treeFind(BinaryTree* head,DataType value)
{
    if(head == NULL)
    {
        return NULL;
    }
    if(head->data == value)
    {
        return head;
    }
    BinaryTree* lfind = treeFind(head->lchild,value);
    BinaryTree* rfind = treeFind(head->rchild,value);
    if(lfind != NULL)
    {
        return lfind;
    }
    if(rfind != NULL)
    {
        return rfind;
    }
    return NULL;
}

//查左子树
BinaryTree* treeLChild(BinaryTree* head)
{
    if(head == NULL)
    {
        return NULL;
    }
    return head->lchild;
}

//查右子树
BinaryTree* treeRChild(BinaryTree* head)
{
    if(head == NULL)
    {
        return NULL;
    }
    return head->rchild;
}

//查双亲节点
BinaryTree* treeParent(BinaryTree* head,BinaryTree* child)
{
    if(head == NULL || child == NULL)
    {
        return NULL;
    }
    if(head == child)
    {
        return NULL;
    }
    if(head->lchild == child || head->rchild == child )
    {
        return head;
    }
    BinaryTree* lchild = treeParent(head->lchild,child);
    BinaryTree* rchild = treeParent(head->rchild,child);
    return lchild != NULL? lchild:rchild;//三目操作符
}


//------------------------------------------------------------------
//------测试函数
//------------------------------------------------------------------

void testtreeorder()
{
    LINE1;
    BinaryTree* a = CreateNode('a');
    BinaryTree* b = CreateNode('b');
    BinaryTree* c = CreateNode('c');
    BinaryTree* d = CreateNode('d');
    BinaryTree* e = CreateNode('e');
    BinaryTree* f = CreateNode('f');
    BinaryTree* g = CreateNode('g');

    a->lchild = b;
    a->rchild = c;
    b->lchild = d;
    b->rchild = e;
    e->lchild = g;
    c->rchild = f;

    printf("三种常见遍历:\n");
    printf("先序遍历:");
    treepreorder(a);
    printf("\n");
    printf("中序遍历:");
    treeiorder(a);
    printf("\n");
    printf("后序遍历:");
    treepostorder(a);
    printf("\n");
}

void testtreelevorder()
{
    LINE1;
    BinaryTree* a = CreateNode('a');
    BinaryTree* b = CreateNode('b');
    BinaryTree* c = CreateNode('c');
    BinaryTree* d = CreateNode('d');
    BinaryTree* e = CreateNode('e');
    BinaryTree* f = CreateNode('f');
    BinaryTree* g = CreateNode('g');

    a->lchild = b;
    a->rchild = c;
    b->lchild = d;
    b->rchild = e;
    e->lchild = g;
    c->rchild = f;

    printf("层序遍历:\n");
    seqqueue queue;
    seqqueueInit(&queue);
    printf("层序遍历:");
    treelevelorder(a,&queue);
    printf("\n");
}

void testpreorderCreate()
{
    LINE1;
    DataType buf[] = "abd##eg###c#f##";
    size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
    BinaryTree* head = preorderCreate(buf,size);

    printf("根据先序遍历还原二叉树:\n");
    printf("先序遍历:");
    treepreorder(head);
    printf("\n");
    printf("中序遍历:");
    treeiorder(head);
    printf("\n");
    printf("后序遍历:");
    treepostorder(head);
    printf("\n");
}

void testtreeCopy()
{
    LINE1;
    DataType buf[] = "abd##eg###c#f##";
    size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
    BinaryTree* head = preorderCreate(buf,size);

    BinaryTree* new_node = treeCopy(head);

    printf("二叉树拷贝:\n");
    printf("先序遍历:");
    treepreorder(new_node);
    printf("\n");
    printf("中序遍历:");
    treeiorder(new_node);
    printf("\n");
    printf("后序遍历:");
    treepostorder(new_node);
    printf("\n");
}

void testtreeNodeSize()
{
    LINE1;
    DataType buf[] = "abd##eg###c#f##";
    size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
    BinaryTree* head = preorderCreate(buf,size);

    printf("二叉树节点总数:%d\n",treeNodeSize(head));
}

void testtreeleftSize()
{
    LINE1;
    DataType buf[] = "abd##eg###c#f##";
    size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
    BinaryTree* head = preorderCreate(buf,size);

    printf("二叉树叶子节点总数:%d\n",treeleftSize(head));
}

void testtreeKLevelSize()
{
    LINE1;
    int K = 3;
    DataType buf[] = "abd##eg###c#f##";
    size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
    BinaryTree* head = preorderCreate(buf,size);

    printf("二叉树第%d层节点总数:%d\n",K,treeKLevelSize(head,K));
}

void testtreeHeight()
{
    LINE1;
    DataType buf[] = "abd##eg###c#f##";
    size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
    BinaryTree* head = preorderCreate(buf,size);

    printf("二叉树深度:%d\n",treeHeight(head));

}

void testtreeFind()
{
    LINE1;
    DataType buf[] = "abd##eg###c#f##";
    size_t size = sizeof(buf)/sizeof(buf[0]) - 1;
    BinaryTree* head = preorderCreate(buf,size);

    printf("寻找元素在二叉树中的节点:\n");
    BinaryTree* cur = treeFind(head,'f');
    printf("正常测试\n");
    printf("预计值:[%c|%p],实际值:[%c|%p]\n",head->rchild->rchild->data
            ,&(head->rchild->rchild->data),cur->data,&(cur->data));

    BinaryTree* cur1 = treeFind(head,'z');
    printf("错误测试\n");
    printf("预计值: NULL ,实际值:%p\n",cur1);;
}

void testtreeChild()
{
    LINE1;
    BinaryTree* a = CreateNode('a');
    BinaryTree* b = CreateNode('b');
    BinaryTree* c = CreateNode('c');
    BinaryTree* d = CreateNode('d');
    BinaryTree* e = CreateNode('e');
    BinaryTree* f = CreateNode('f');
    BinaryTree* g = CreateNode('g');

    a->lchild = b;
    a->rchild = c;
    b->lchild = d;
    b->rchild = e;
    e->lchild = g;
    c->rchild = f;

    BinaryTree* lchild = treeLChild(b);
    BinaryTree* rchild = treeRChild(b);
    BinaryTree* lchild1 = treeLChild(f);
    BinaryTree* rchild1 = treeRChild(f);

    printf("求节点的左右节点:\n");
    printf("正常测试\n");
    printf("左节点预计值:[%c|%p],实际值[%c|%p]\n",
            b->lchild->data,&(b->lchild->data),lchild->data,&(lchild->data));
    printf("右节点预计值:[%c|%p],实际值:[%c|%p]\n",
            b->rchild->data,&(b->rchild->data),rchild->data,&(rchild->data));
    printf("错误测试\n");
    printf("左节点预计值: NULL ,实际值:%p\n",lchild1);
    printf("右节点预计值: NULL ,实际值:%p\n",rchild1);
}

void testtreeParent()
{
    LINE1;
    BinaryTree* a = CreateNode('a');
    BinaryTree* b = CreateNode('b');
    BinaryTree* c = CreateNode('c');
    BinaryTree* d = CreateNode('d');
    BinaryTree* e = CreateNode('e');
    BinaryTree* f = CreateNode('f');
    BinaryTree* g = CreateNode('g');

    a->lchild = b;
    a->rchild = c;
    b->lchild = d;
    b->rchild = e;
    e->lchild = g;
    c->rchild = f;

    BinaryTree* parent = treeParent(a,g);
    printf("求节点的双亲节点:\n");
    printf("预计值:[%c|%p],实际值:[%c|%p]\n",e->data,&(e->data),parent->data,&(parent->data));
}

int main()
{
    testtreeorder();
    testtreelevorder();
    testpreorderCreate();
    testtreeCopy();
    testtreeNodeSize();
    testtreeleftSize();
    testtreeKLevelSize();
    testtreeHeight();
    testtreeFind();
    testtreeChild();
    testtreeParent();
    return 0;
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/q496958148/article/details/80143698