链式二叉树

链式二叉树结构

链式二叉树其结构包括两个部分,一个是数据域还有指针域(指针域有两个,一个指针保存其左子树地址,另一个指针保存其右子树)。二叉树总是由根,左子树和右子树组成,因而叉树是递归定义的。二叉树是一种特殊的树形数据结构,它的每个结点最多有两个子结点,分别称为左子树结点和右子树结点。二叉树可以是空的,也就是不包含任何结点;或者是由根结点、左子树和右子树三部分组成。

链式二叉树结构定义:

typedef int BTDataType;//二叉树节点存储类型
typedef struct BinaryTreeNode
{
 BTDataType data;//该节点的值
 struct BinaryTreeNode* left;//左子树节点地址
 struct BinaryTreeNode* right;//右子树节点地址
}BTNode;

二叉树的遍历

二叉树遍历(Traversal)是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为前序遍历(先根遍历)、中序遍历(中根遍历)和后序遍历(后根遍历)。二叉树的遍历包含前序遍历,中序遍历和后序遍历以及层序遍历。
为了实现二叉树的各种遍历我们采用手动构建一颗二叉树。其代码如下:

BTNode* createbinarytree()
{
    BTNode* root1 = (BTNode*)malloc(sizeof(BTDataType));
    BTNode* root2 = (BTNode*)malloc(sizeof(BTDataType));
    BTNode* root3 = (BTNode*)malloc(sizeof(BTDataType));
    BTNode* root4 = (BTNode*)malloc(sizeof(BTDataType));
    BTNode* root5 = (BTNode*)malloc(sizeof(BTDataType));
    BTNode* root6 = (BTNode*)malloc(sizeof(BTDataType));
    BTNode* root7 = (BTNode*)malloc(sizeof(BTDataType));
    root1->data = 1;
    root2->data = 3;
    root3->data = 5;
    root4->data = 2;
    root5->data = 4;
    root6->data = 6;
    root7->data = 8;
    root1->left = root2;
    root1->right = root3;
    root2->left = root4;
    root2->right = root5;
    root3->left = root6;
    root3->right = root7;
    root4->left = NULL;
    root4->right = NULL;
    root5->left = NULL;
    root5->right = NULL;
    root6->left = NULL;
    root6->right = NULL;
    root7->left = NULL;
    root7->right = NULL;
    return root1;
}

构建的二叉树其逻辑结构如下:
在这里插入图片描述

二叉树前序遍历

二叉树前序遍历(又称先序遍历)的规则是根节点,左子树,右子树。进行遍历的时候不断将其划分成根,左子树,右子树。所以根据这个遍历顺序我们采用递归的方式。

二叉树前序遍历代码如下:

void preordertraversal(BTNode*root)
{
    if (root == NULL)//当根为NULL返回
    {
        printf("N ");
        return;
    }
    printf("%d ", root->data);//先访问根节点
    preordertraversal(root->left);//访问左子树
    preordertraversal(root->right);//访问右子树
}

二叉树中续遍历

二叉树中序遍历的规则是左子树,根节点,右子树。进行遍历的时候不断将其划分成左子树,根,右子树。所以根据这个遍历顺序我们采用递归的方式。

二叉树中序遍历代码如下:

//中序遍历
void inordertraversal(BTNode* root)
{
    if (root == NULL)//当根为NULL返回
    {
        printf("N ");
        return;
    }
    inordertraversal(root->left);//访问左子树
    printf("%d ", root->data);//访问根节点
    inordertraversal(root->right);//访问右子树
}

二叉树后续遍历

二叉树后序遍历的规则是左子树,右子树和根节点。进行遍历的时候不断将其划分成左子树,右子树,根。所以根据这个遍历顺序我们采用递归的方式

二叉树后序遍历代码如下:

//后续遍历
void postordertraversal(BTNode* root)
{
    if (root == NULL)//当根为NULL返回
    {
        printf("N ");
        return;
    }
    postordertraversal(root->left);//访问左子树
    postordertraversal(root->right);//访问右子树
    printf("%d ", root->data);//访问根节点
}

二叉树层序遍历

二叉树层序遍历:设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。二叉树的层序遍历需要借助队列,队列中存储的是节点的地址,当该节点访问之后进行出队列同时将该节点的左子树和右子树的地址入队列(该节点出队列同时带该节点的左右节点,若是空就不入队列)。层序遍历顺序的示意图如下所示:
在这里插入图片描述

队列代码(queue.h)

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
//#include"vld.h"
typedef int BTDataType;//二叉树节点存储类型
typedef struct BinaryTreeNode
{
    BTDataType data;//该节点的值
    struct BinaryTreeNode* left;//左子树节点地址
    struct BinaryTreeNode* right;//右子树节点地址
}BTNode;
typedef BTNode* queuedatatype;

//定义队列中的节点结构
typedef struct queuenode
{
    queuedatatype data;//存放数据
    struct queuenode* next;//存放写一个节点的地址
}queuenode;

//定义队列结构
typedef struct queue
{
    queuenode* qhead;//队列的头节点
    queuenode* qtail;//队列尾节点
    int size;//当前队列中所存放的数据个数
}queue;

//队列初始化
void queueinit(queue* pq);

//入队列
void queuepush(queue* pq, queuedatatype data);

//取队头数据
queuedatatype queuefront(queue* pq);

//取队尾数据
queuedatatype queueback(queue* pq);

//删除队头数据
void queuepop(queue* pq);

//队列为空返回true
bool queueempty(queue* pq);

//返回队列中的数据个数
int queuesize(queue* pq);

//队列销毁
void queuedestroy(queue* pq);

队列代码(queue.c)

#define _CRT_SECURE_NO_WARNINGS 1
#include"queue.h"

//队列初始化
void queueinit(queue* pq)
{
    assert(pq);
    pq->qhead = NULL;//队头置NULL
    pq->qtail = NULL;//队尾置NULL
    pq->size = 0;//初始时队列中的元素个数为0
}

//入队列
void queuepush(queue* pq, queuedatatype data)
{
    assert(pq);
    //不管队列是空还是有数据都需要开一个节点的空间
    queuenode* newnode = (queuenode*)malloc(sizeof(queuenode));
    if (newnode == NULL)//开辟失败
    {
        perror("malloc");//开辟空间失败打印提示信息
        return;
    }
    //将数据存放在新节点中的data中并将新节点的next置空
    newnode->data = data;
    newnode->next = NULL;
    if (pq->qhead == NULL)//队列为空
    {
        pq->qhead = pq->qtail = newnode;
    }
    else//队列不为空
    {
        pq->qtail->next = newnode;//将当前尾节点的next指向下一个
        pq->qtail = newnode;//尾节点指向新节点
    }
    pq->size++;//队列入一个数据,size+1
}

//取队头数据
queuedatatype queuefront(queue* pq)
{
    assert(pq);
    assert(pq->size > 0);//当前队列中还有数据,没有数据就报错
    return pq->qhead->data;//有数据就直接返回队头数据
}

//取队尾数据
queuedatatype queueback(queue* pq)
{
    assert(pq);
    assert(pq->size > 0);//当前队列中是否还有数据,没有数据就报错
    return pq->qtail->data;//有数据就直接返回队尾数据
}

//删除队头数据
void queuepop(queue* pq)
{
    assert(pq);
    assert(pq->size > 0);//当前队列中是否还有数据,没有数据就报错
    queuenode* del = pq->qhead;//将要删除的节点的地址存下来
    if (pq->qhead == pq->qtail)//此时只有一个节点
    {
        pq->qhead = pq->qtail = NULL;//只有一个节点就将指向队头和队尾的指针都置空
    }
    else//此时有多个节点
    {
        pq->qhead = pq->qhead->next;//让队头指针指向下一个节点
    }
    pq->size--;
    free(del);//释放节点
}

//队列为空返回true
bool queueempty(queue* pq)
{
    assert(pq);
    //如果size为0就表示队列为空就返回true否则返回false
    return pq->size == 0;
}

//返回队列中的数据个数
int queuesize(queue* pq)
{
    assert(pq);
    return pq->size;//直接返回size
}

//队列销毁
void queuedestroy(queue* pq)
{
    assert(pq);
    queuenode* del = pq->qhead;
    while (del)//通过链表的遍历,依次释放节点
    {
        queuenode* next = del->next;//保存下一个节点
        free(del);//释放当前节点
        del = next;//让del指向下一个节点
    }
    pq->qhead = NULL;//队头指针置空
    pq->qtail = NULL;//队尾指针置空
    pq->size = 0;//队列中元素个数置0
}

层序遍历代码实现如下:

//层序遍历
void levelordertraversal(BTNode* root)
{
    if (root == NULL)
    {
        return;
    }
    queue q;//创建一个队列
    queueinit(&q);//队列初始化
    queuepush(&q, root);
    while (!queueempty(&q))//队列不为空就继续
    {
        BTNode* root = queuefront(&q);
        queuepop(&q);
        printf("%d ", root->data);
        if (root->left)
            queuepush(&q, root->left);
        if (root->right)
            queuepush(&q, root->right);
    }
    queuedestroy(&q);//销毁队列
}

二叉树节点个数和高度等

这部分主要介绍求二叉树节点个数,叶子结点个数,第k层节点个数和查找值为x 的节点。

二叉树节点个数

求二叉树的节点个数主要思路是该节点加上该节点的左子树节点个数和右子树节点个数。所以我们采用递归的方式来实现。其代码实现如下:

// 二叉树结点个数
int BinaryTreeSize(BTNode* root)
{
    if (root == NULL)
        return 0;//当节点为空就返回0
    //左子树节点个数+右子树节点个数+1
    return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

二叉树叶子节点个数

求二叉树叶子节点个数的思路是其主要思路也是递归,要求该二叉树中叶子节点的个数那就求该二叉树中左右子树中叶子节点的个数。我们采用递归的方式,代码实现如下:

// 二叉树叶子结点个数
int BinaryTreeLeafSize(BTNode* root)
{
    if (root == NULL)//当前节点为NULL就返回0
        return 0;
    if (root->left == NULL && root->right == NULL)//如果该节点为叶子节点就返回1
        return 1;
    //如果该节点不为叶子节点就求其左子树的叶子结点个数与其右子树的叶子结点个数之和
    return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

二叉树第k层节点个数

求二叉树第k层节点的个数的思路是要求第k层节点的个数那就求该节点的左右子树的第k-1层节点,所以对于求第k层节点个数的个数我们采用递归的方式,其代码实现如下:

// 二叉树第k层结点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
    if (root == NULL)//如果该接地那为NULL就返回0
        return 0;
    if (k == 1)//k==1表示该节点是第k层的节点,返回1
        return 1;
    //返回第k-1层的左子树节点与第k-1层的右子树节点之和
    return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

单值二叉树

单值二叉树Leetcode
判断一棵树是否是单值二叉树也是用递归的思路,需要判断根节点与其左节点和右节点是否与根节点的值相同(当根节点为NULL返回true),如果相同就递归其左子树和右子树。如果左节点或右节点与根节点的值不相等就返回false。代码实现如下:

//单值二叉树
bool isUnivalTree(struct TreeNode* root)
{
    if (root == NULL)//当前节点如果为NULL就返回true
        return true;
    if (root->left == NULL && root->right == NULL)//左右节点都为NULL返回true
        return true;
    //如果左节点不为空且左节点的值不等于本节点的值就返回false
    if (root->left != NULL&&root->val!=root->left->val)
    {
        return false;
    }
    //如果右节点不为空且右节点的值不等于本节点的值就返回false
    if (root->right != NULL && root->val != root->right->val)
    {
        return false;
    }
    //如果本节点和其左节点和右节点都是单值,那就递归其左子树和右子树
    return isUnivalTree(root->left) && isUnivalTree(root->right);
}

对称二叉树

对称二叉树Leetcode
要判断一棵树是否是对称二叉树同样需要递归。对称二叉树需要一个子函数来进行处理,该子函数需要两个节点的地址(分别是根节点的左节点和右节点),通过这个子函数进行递归。其代码的实现如下:

//对称二叉树
//子函数递归
bool _isSymmetric(struct TreeNode* root1, struct TreeNode* root2)
{
    if (root1 == NULL && root2 == NULL)//左右节点都为NULL返回true
        return true;
    if (root1 == NULL || root2 == NULL)//此时表示有一个节点不为NULL这表示不对称返回false
        return false;
    if (root1->val != root2->val)//左右节点的值不相等表示不对称返回true
        return false;
    //到这里就表示左右节点相等,对左子树和右子树进行递归
    return _isSymmetric(root1->left, root2->right) && _isSymmetric(root1->right, root2->left);
}
bool isSymmetric(struct TreeNode* root)
{
    if (root == NULL)//如果树的根节点为NULL返回true
        return true;
    //调用子函数
    return _isSymmetric(root->left, root->right);
}

相同的二叉树

相同的二叉树Leetcode
要判断两颗二叉树树是否是相同的二叉树,首先需判断其根节点是否是相同的,然后递归判断其左节点和右节点。其代码实现如下:

//相同的二叉树
bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    //两棵树均为NULL表示两棵树是相同的,返回true
    if (p == NULL && q == NULL)
        return true;
    //只要有一颗树不为空就表示两颗数不同返回false
    if (p == NULL || q == NULL)
        return false;
    //此时表示两颗数都存在,如果节点值不同就返回false
    if (p->val != q->val)
        return false;
    //此时表示两个节点的值相同,进行判断其子树,递归
    return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

二叉树的前序遍历

二叉树前序遍历Leetcode
二叉树的前序遍历,其思想也是递归。但需要注意的是需要将二叉树的前序遍历的值依次存放在数组中,这就需要动态开辟一个数组(这个数组开辟的大小首先需要计算这颗二叉树节点的个数),遍历的过程中需要用一个下标变量,这个下标变量将遍历的值依次存放到数组中。由于下标需要在一次递归调用函数完成之后+1操作(形参是实参的拷贝,要想改变实参需要传地址),所以我们采用传地址的方式。计算树的节点个数 (tresssize 函数),通过递归的方式计算二叉树的节点总数。如果当前节点为 NULL,即表示到达了树的边界,函数返回0。对于每个非空节点,函数将计算其左子树和右子树的节点数,并将它们相加,再加上当前节点本身(即1)。这样,通过递归调用,最终能够得到整棵树的节点总数。使用 tresssize 函数计算树的节点总数,这个数值将被用来分配存储结果的数组。动态分配一个数组来存储前序遍历的结果。如果内存分配失败,则返回 NULL。使用一个辅助函数 _preorderTraversal 来递归地进行前序遍历。这个辅助函数接受当前节点、结果数组以及一个指针 i(用于跟踪结果数组的当前索引位置)。前序遍历的顺序是:首先访问根节点,然后递归访问左子树,最后递归访问右子树。在访问每个节点时,将节点的值添加到结果数组中,并更新索引 i。
完成遍历后,返回存储了遍历结果的数组。其代码的实现如下:

//计算树的节点个数
int tresssize(struct TreeNode* root)
{
    if(root==NULL)//如果节点为NULL返回0
        return 0;
    //如果节点
    return tresssize(root->left)+tresssize(root->right)+1;
}
void _preorderTraversal(struct TreeNode* root,int*ret,int*pi)
{
    if(root==NULL)
    {
        return;
    }
    ret[(*pi)++]=root->val;
    _preorderTraversal(root->left,ret,pi);
    _preorderTraversal(root->right,ret,pi);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{
    if (root == NULL)
    {
        *returnSize = 0;
        return NULL;
    }
    *returnSize = tresssize(root);//计算二叉树的节点个数
    int* ret = (int*)malloc(sizeof(int) * (*returnSize));
    if (ret == NULL) 
    {
        *returnSize = 0;
        return NULL;
    }
    int i = 0;
    _preorderTraversal(root, ret, &i);
    return ret;
}

二叉树的中序遍历

二叉树的中序遍历Leetcode
二叉树的中序遍历和前序遍历的思路类似的,需要注意的就是遍历节点的先后次序。其代码实现如下

int tresssize(struct TreeNode* root)
{
    if(root==NULL)//如果节点为NULL返回0
        return 0;
    //如果节点
    return tresssize(root->left)+tresssize(root->right)+1;
}
void _inorderTraversal(struct TreeNode* root,int*ret,int*pi)
{
    if(root==NULL)
    {
        return;
    }
    _inorderTraversal(root->left,ret,pi);
    ret[(*pi)++]=root->val;
    _inorderTraversal(root->right,ret,pi);
}
int* inorderTraversal(struct TreeNode* root, int* returnSize) 
{
    if (root == NULL)
    {
        *returnSize = 0;
        return NULL;
    }
    *returnSize = tresssize(root);//计算二叉树的节点个数
    int* ret = (int*)malloc(sizeof(int) * (*returnSize));
    if (ret == NULL) 
    {
        *returnSize = 0;
        return NULL;
    }
    int i = 0;
    _inorderTraversal(root, ret, &i);
    return ret;
}

二叉树的后序遍历

二叉树的后序遍历实现的思路与上面的前序和中序遍历一致,需要注意的就是遍历节点的先后次序
二叉树的后序遍历Leetcode

int tresssize(struct TreeNode* root)
{
    if(root==NULL)//如果节点为NULL返回0
        return 0;
    //如果节点
    return tresssize(root->left)+tresssize(root->right)+1;
}
void _postorderTraversal(struct TreeNode* root,int*ret,int*pi)
{
    if(root==NULL)
    {
        return;
    }
    _postorderTraversal(root->left,ret,pi);
    _postorderTraversal(root->right,ret,pi);
    ret[(*pi)++]=root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize) 
{
    if (root == NULL)
    {
        *returnSize = 0;
        return NULL;
    }
    *returnSize = tresssize(root);//计算二叉树的节点个数
    int* ret = (int*)malloc(sizeof(int) * (*returnSize));
    if (ret == NULL) 
    {
        *returnSize = 0;
        return NULL;
    }
    int i = 0;
    _postorderTraversal(root, ret, &i);
    return ret;
}

另一棵树的子树

另一颗树的子树Leetcode
判断一棵树是否是另一颗树的子树,其思路也是递归。
isSameTree 函数检查两棵树是否相同。它首先检查如果两个树的根节点都是 NULL,则返回 true(表示两个空树显然相同)。如果其中一个为空而另一个不为空,则返回 false。如果两个节点的值不相同,也返回 false。只有当当前两个节点的值相同,并且它们的左右子树也分别相同的时候,才返回 true。
isSubtree 函数用来检查 subRoot 是否是 root 的一个子树。它首先检查 root 是否为空,如果为空则返回 false(空树不能包含任何子树)。然后,如果当前 root 的值与 subRoot 的值相同,并且它们是相同的树,就返回 true。如果不是,就递归地检查 root 的左子树和右子树是否包含 subRoot

//是否是相同的树
bool isSametree(struct TreeNode* root, struct TreeNode* subRoot)
{
    if(root==NULL&&subRoot==NULL)
    {
        return true;
    }
    if(root==NULL||subRoot==NULL)//两棵树有一个不为空就表示不是同一棵树
    {
        return false;
    }
    if(root->val!=subRoot->val)
    {
        return false;
    }
    return isSametree(root->left,subRoot->left)&&isSametree(root->right,subRoot->right);
}
//判断subRoot是否是root的子树
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    if(root==NULL)//如果遍历了所以节点还不匹配那就返回false表示subRoot不是root的子树
        return false;
    //如果节点的值与subRoot节点的值相等并且是同一棵树就返回true
    if(root->val==subRoot->val&&isSametree(root,subRoot))
    {
        return true;
    }
    //如果上面的没返回那就递归其左右子树
    return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}

二叉树的创建和销毁

二叉树的构建和遍历Leetcode
createbinarytree函数通过递归的方式从一个字符串数组中创建一个二叉树。字符串数组中的字符代表节点的值,#字符代表空节点。函数首先检查当前字符是否为#,如果是,表示当前位置应该是一个空节点,因此返回NULL并递增索引pi。如果当前字符不是#,则创建一个新的树节点,并将当前字符赋值给节点的val属性,同时递增索引pi。接着,函数递归调用自身来创建左子树和右子树。这些递归调用分别将创建好的子树赋值给当前节点的left和right指针。最后,函数返回创建好的树节点。
中序遍历 (inordertraversal 函数)这个函数对二叉树进行中序遍历,遍历顺序是:先遍历左子树,然后访问根节点,最后遍历右子树。
函数首先检查当前节点是否为空,如果为空,则返回;否则,先递归遍历左子树,然后输出当前节点的值,最后递归遍历右子树。
其代码实现如下:

#include <stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct treenode 
{
    char val;
    struct treenode* left;
    struct treenode* right;
} treenode;
treenode* createbinarytree(char* arr, int* pi) 
{

    if (arr[*pi] == '#')//当前是否是空节点,不能arr[(*pi)++],否则出现越界问题
    {
        (*pi)++;//注意*pi在这个里面++
        return NULL;//返回NULL
    }
    treenode* tmp = (treenode*)malloc(sizeof(treenode));
    tmp->val = arr[(*pi)++];
    tmp->left = createbinarytree(arr, pi);//将左子树节点给tmp->left
    tmp->right = createbinarytree(arr, pi);//将右子树节点给tmp->left
    return tmp;//返回tmp
}
void inordertraversal(treenode* root) 
{
    if (root == NULL) 
    {
        return;
    }
    inordertraversal(root->left);
    printf("%c ", root->val);
    inordertraversal(root->right);
}
int main() 
{
    char str[100] = {0};
    scanf("%s",str);
    int size = strlen(str); //计算节点个数包括空节点
    int i = 0;
    treenode* root = createbinarytree(str, &i);
    inordertraversal(root);
    return 0;
}

判断二叉树是否是完全二叉树

是否是完全二叉树Leetcode
要判断一棵树是否是完全二叉树需要使用到队列。父节点出队列后要将这个父节点对应的子节点进入队列,当队列出到空节点时判断当前队列是否还有不为空的节点,如果有不为空的节点就表示不是完全二叉树,如果队列中都是空间点那就表示该二叉树是完全二叉树。首先需要实现一个队列然后通过类似层序遍历的方法出入队列。代码实现如下:

#include<assert.h>
typedef struct queuenode
{
    struct TreeNode* val;
    struct queuenode*next;
}queuenode;
typedef struct queue
{
    queuenode*qhead;
    queuenode*qtail;
    int size;
}queue;
void queueinit(queue*pq)
{
    pq->qhead=pq->qtail=NULL;
    pq->size=0;
}
void queuepush(queue*pq,struct TreeNode* val)
{
    queuenode*newnode=(queuenode*)malloc(sizeof(queuenode));
    newnode->val=val;
    newnode->next=NULL;
    if(pq->qhead==NULL)
    {
        pq->qhead=pq->qtail=newnode;
    }
    else 
    {
        pq->qtail->next=newnode;
        pq->qtail=newnode;
    }
    pq->size++;
}
struct TreeNode* queuefront(queue*pq)
{
    return pq->qhead->val;
}
void queuepop(queue*pq)
{
    assert(pq->size>0);
    queuenode*next=pq->qhead->next;
    free(pq->qhead);
    if(pq->qhead==pq->qtail)
    {
        pq->qhead=pq->qtail=next;
    }
    else 
    {
        pq->qhead=next;
    }
    pq->size--;    
}
void queuedestory(queue*pq)
{
    queuenode*del=pq->qhead;
    while(del)
    {
        queuenode*next=del->next;
        free(del);
        del=next;
    }
    pq->qhead=pq->qtail=NULL;
    pq->size=0;
}
int queuesize(queue*pq)
{
    return pq->size;
}
bool isCompleteTree(struct TreeNode* root) 
{
    //创建一个队列
    queue qu;
    queueinit(&qu);
    //入队列
    queuepush(&qu,root);
    while(queuesize(&qu)>0)
    {
        struct TreeNode*tmp=queuefront(&qu);
        queuepop(&qu);
        if(tmp==NULL)
        {
            break;//队列出到空就退出循环
        }
        //如下一层的节点
        queuepush(&qu,tmp->left);
        queuepush(&qu,tmp->right);
    }
    //看队列中是否还有不为NULL节点,如果有则表示不是完全二叉树
    while(queuesize(&qu)>0)
    {
        struct TreeNode*tmp=queuefront(&qu);
        queuepop(&qu);
        if(tmp!=NULL)
        {
            queuedestory(&qu);
            return false;
        }
    }
    queuedestory(&qu);
    return true;
}

二叉树的销毁

对于二叉树的销毁,我们依然采用递归的思路,但二叉树的销毁采用的后序进行递归的(先销毁左子树再销毁右子树最后在销毁根节点)。二叉树的销毁代码实现如下:

//二叉树的销毁
void BinaryTreeDestory(BTNode** root)
{
    if (*root == NULL)//如果root为NULL就直接返回
        return;
    BinaryTreeDestory(&(*root)->left);//释放左子树
    BinaryTreeDestory(&(*root)->right);//释放右子树
    free(*root);//释放根节点
    *root == NULL;//将根节点置空
}

总结:本文主要介绍了二叉树的前序,中序,后序以及层序遍历。还介绍了一些关于二叉树部分的基础oj题,如单值二叉树,是否是同一棵树,是否是对称二叉树,二叉树的构建,是否是完全二叉树等(大部分题其核心都是通过递归的方式来实现的,少数题需要借助到队列)。感谢大家的观看,如有错误不足之处欢迎大家批评指正!!!

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值