二叉树的实现

二叉树,顾名思义一个节点最多只有两个节点,且有左右之分,是树形结构中重要的一种结构

数据定义:

typedef char BTDataType;//节点的数据类型
typedef struct BinaryTreeNode
{
	BTDataType _data;//数据
	struct BinaryTreeNode* _left;//左节点
	struct BinaryTreeNode* _right;//右节点
}BTNode;

二叉树的遍历总共有四种,以下列二叉树为例,分别实现前/中/后/层序遍历:

            A      
          /   \
         B     C   
        / \   / \
       D   E  F  G
            \ 
             H

前序遍历:根,左节点,右节点

void BinaryTreePrevOrder(BTNode* root)
{
    if(root==NULL)
    {
        printf("NULL ");
        return;
    }
    printf("%c ",root->_data);    //打印根
    BinaryTreePrevOrder(root->_left);   //递归到最底层后,打印最底层的左右节点
    BinaryTreePrevOrder(root->_right);
}

打印值:A B D NULL NULL E NULL H NULL NULL C F NULL NULL G NULL NULL

中序遍历:左节点,根,右节点

void BinaryTreeInOrder(BTNode* root)
{
    if(root==NULL)
    {
        printf("NULL ");
        return;
    }
    BinaryTreeInOrder(root->_left);
    printf("%c ",root->_data);        //和前序遍历差不多 只不过是把根放到了中间
    BinaryTreeInOrder(root->_right);
}

打印值:NULL D NULL B NULL E NULL H NULL A NULL F NULL C NULL G NULL 

后序遍历:左节点,右节点,根

void BinaryTreePostOrder(BTNode* root)
{
    if(root==NULL)
    {
        printf("NULL ");
        return;
    }
    BinaryTreePostOrder(root->_left);
    BinaryTreePostOrder(root->_right);
    printf("%c ",root->_data);        //后序遍历也是一样 只需移动根节点的输出
}

打印值:NULL NULL D NULL NULL NULL H E B NULL NULL F NULL NULL G C A 

前/中/后序遍历的原理是一样的,都是利用递归到最后一个有效节点的左右孩子的位置,判断是否为NULL,如果为NULL则开始打印那个节点的值,不同的是打印的顺序。

但是层序遍历不一样,它无法使用递归实现,它是从左往右依次遍历所有节点,它的实现需要用到队列来帮助。

思路:先push根节点,然后判断根节点的左右孩子是否为空,如果为空则不入列,如果不为空就入列,然后队列入一个值打印一个值,再立刻出列pop掉,为什么要立刻出列呢,是因为可以用判断队列是否为空来控制循环,当队列为空时,则证明已经遍历了树的所有节点。

具体实现如下:

定义队列以及实现队列:

typedef BTNode* QDataType;//定义队列中数据的类型
//二叉树队列
typedef struct QListNode 
{ 
	struct QListNode* _next; 
	QDataType _data; 
}QNode; 


//队列的实现 Queue.c

// 队列的结构 
typedef struct Queue 
{ 
	QNode* front; //队头
	QNode* rear;  //队尾
    int size;//计数
}Queue;
 
// 初始化队列 
void QueueInit(Queue* q)
{
    q->front=NULL;
    q->rear=NULL;
    q->size=0;
}

// 队尾入队列 
void QueuePush(Queue* q, QDataType data)
{
    assert(q);
    QNode* newNode=(QNode*)malloc(sizeof(QNode));
    if(newNode==NULL)
    {
        perror("malloc fail:");
        exit(-1);
    }
    newNode->_data=data;
    newNode->_next=NULL;

    if(q->rear==NULL)//front和rear未指向时 赋值newNode给它们当第一个值
    {
        q->front=q->rear=newNode;
    }
    else
    {
        q->rear->_next=newNode;//尾插
        q->rear=q->rear->_next;
    }
    q->size++;//计数
} 

// 队头出队列 
void QueuePop(Queue* q)
{
    assert(q);
    if(q->front->_next==NULL)//只有一个元素时 出列(释放) 置NULL
    {
        free(q->front);
        q->front=q->rear=NULL;
    }
    else//多元素时出列后 front往后移
    {
        QNode* del =q->front;
        q->front=del->_next;
        free(del);
    }
    q->size--;
} 

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
    assert(q);
    assert(!QueueEmpty(q));

    return q->front->_data;
}



// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
    assert(q);
    return q->front==NULL &&q->rear==NULL;
}

// 销毁队列 
void QueueDestroy(Queue* q)
{
    assert(q);
    while(q->size)
    {
        QueuePop(q);//销毁就是一直出列
    }
}

层序遍历:一层一层依次从左到右遍历所有节点

void BinaryTreeLevelOrder(BTNode* root)
{
    Queue q;
    QueueInit(&q);
    if(root!=NULL)  QueuePush(&q,root);//树不为空 插入根节点
    while(!QueueEmpty(&q))//为空
    {
        QDataType front = QueueFront(&q);//BTNode*=QDataType
            printf("%c ",front->_data);
            QueuePop(&q);//出列
        if(front->_left!=NULL)
        {
            QueuePush(&q,front->_left);//左子节点不为空则入列
        }
        if(front->_right!=NULL)
        {
            QueuePush(&q,front->_right);//右子节点不为空则入列
        }
    }
    printf("\n");
    QueueDestroy(&q);
}

打印值:A B C D E F G H 

实现过遍历后,也能通过遍历来实现二叉树的创建,这里拿前序遍历来构建二叉树

前序遍历数组"ABD##E#H##CF##G##"构建二叉树

以及二叉树的销毁

BTNode* BinaryTreeCreate(BTDataType* a,int* p)
{
    BTNode* Tree = (BTNode*)malloc(sizeof(BTNode));
    if(a[*p]=='#')
    {
        (*p)++;
        return NULL;
    }
        Tree->_data=a[(*p)++];    //和遍历原理一样
        Tree->_left=BinaryTreeCreate(a,p);
        Tree->_right=BinaryTreeCreate(a,p);
    return Tree;
}


// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
    if(*root==NULL) return;
    BinaryTreeDestory(&(*root)->_left);
    BinaryTreeDestory(&(*root)->_right);
    free(*root);   //递归到叶子节点再销毁,否则先销毁前面的节点会导致后面节点无法被找到
}

还可以利用递归,来判断二叉树的总节点数、叶子节点数以及每层的节点数

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
    //静态变量无法释放 第二次调用函数时会接着往上加 用的时候会出现叠加问题,所以不用
    // static int size=0;
    // if(root==NULL) return 0;
    // ++size;
    // BinaryTreeSize(root->_left);
    // BinaryTreeSize(root->_right);
    // return size;

    if(root==NULL) return 0;
    return BinaryTreeSize(root->_left)+
           BinaryTreeSize(root->_right)+1;

    //简写
    //return root==NULL? 0:BinaryTreeSize(root->_left)+BinaryTreeSize(root->_right)+1;
    
}

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{   //为NULL时返回0 结束递归
    if(root==NULL) return 0;
    //节点左右都为NULL时是叶子节点
    if(root->_left==NULL&&root->_right==NULL) return 1;

    return BinaryTreeLeafSize(root->_left)  //左右子树的叶子节点相加即可
          +BinaryTreeLeafSize(root->_right);
}

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
    if(root==NULL)
    {
        return 0;
    }
    if(k==1) //当k=1时 是要计算的层数 如果不为NULL则+1
    {
        return 1;
    }
    return BinaryTreeLevelKSize(root->_left,k-1)+
           BinaryTreeLevelKSize(root->_right,k-1);
    /*      A      相对于A层 DEFG层为第三层 k=3
          /   \
         B     C   相对于BC层 DEFG层为第二层 k-1层 也就是k=2
        / \   / \
       D   E  F  G 相当于DEFG层 DEFG层为第一层 k-1-1层 也就是k=1
            \ 
             H
    计算第三层有几个节点时 k-1层B的子节点数+C的子节点数
    当BC的子节点不为NULL时 就能返回k==1 
    k==1 B的左节点不为NULL 返回1 加上 右节点不为NULL 返回1
    那么子树B(k-1层)有2个节点 同理子树C(k-1层)有2个
    递归回去后 k!=1 root!=NULL 则返回 2 + 2 = 3
    */

}

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
    if(root==NULL) return NULL;
    if(root->_data==x) return root;//递归结束条件
    
    if(BinaryTreeFind(root->_left,x)) //先遍历左子树 
    
        return BinaryTreeFind(root->_left,x);
    
    else            //左子树找不到再遍历右子树

        return BinaryTreeFind(root->_right,x);
    
    //简写
    // BTNode* left=BinaryTreeFind(root->_left,x);
    // BTNode* right=BinaryTreeFind(root->_right,x);
    // return left ? left : right; 
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值