一篇文章教你学会二叉树的链表实现及其oj题(附源码)

前言

前面我们通过堆实现了二叉树,接下来我们用链表实现二叉树。

1. 实现链式结构二叉树

1.1 结构体定义

二叉树的每个结点需要两个指针,分别指向其左孩子和右孩子。还有一个结点域,存储数据。

还是将数据类型重命名,便于后面更改。一个结构体指针指向左孩子,另一个指向右孩子。

1.2 申请结点

由于二叉树的结点都是动态申请的,需要多次,因此我们将它封装为函数便于使用。

先动态申请结点大小的内存,然后判断是否为空,不为空则对其进行初始化,一开始将左右指针都指向空,将数据赋值,最后返回新结点。

1.3 二叉树构建

通过如上代码,我们现实了一个简单二叉树。二叉树如下图:

1.4 求二叉树结点个数

我们通过递归的方式求结点个数,二叉树的很多功能都是用递归实现,二叉树就是关于递归的暴力美学。

如果结点为空,则返回0停止递归,否则就进行递归,返回本身的结点树和左子树的结点数以及右子树的结点数。

分析:当传入第一个结点的时候,结点不为空,则进入递归,到一号结点的左节点及二号结点,该结点不为空,进入递归,到四号结点,四号结点不为空,进入递归,而四号结点的左子树为空,返回0,然后进入四号结点的右子树,也返回0。然后到四号结点,返回1。再到二号结点的右子树,跟四号结点是一种情况,返回1。再到二号结点,返回3。再到三号结点,与四号结点类似,返回1,最后到一号结点,返回5。

1.5 求某层结点的个数

我们知道了某层的层次k,就可以通过一个if循环来判断该结点个数。

k表示第几层,当k不为1时不进行计数,只有当k为1时才进行记录个数。返回的是该结点的左子树和右子树在k层的结点个数。如果没达到k层就为空了,则不计数。

1.6 求叶子结点个数

叶子结点的特征就是左子树和右子树都为NULL,所以如果遇到这样的结点则计数,否则不计数。

1.7 查找值为x的结点

递归结点的左右子树,如果碰到值相等的则返回这个结点,如果一直没遇到则返回空。

通过if递归左右子树。

1.8 求二叉树的层次

我们知道,如果是完全二叉树,则左子树层次一定比右子树的层次深。所以我们递归左子树就可以了。

1.9 二叉树销毁

遍历二叉树,将每个结点都置free并置为空。因为要遍历二叉树,所以不能从根结点开始销毁,如果销毁了就找不到其他的结点了。

因为会销毁头结点,所以需要用到二级指针。

1.10 二叉树层次遍历

层次遍历需要通过队列来实现。

思路:将根结点放入队列中,然后将根结点取出并打印,将根结点的左右不为空的结点放入队列,再依次取出并打印,再放入其左右非空结点。直到队列为空。

这里需要注意,由于需要用到队列,我们需要创建并初始化队列,最后将队列进行销毁。

1.11 判断是否为完全二叉树

判断完全二叉树也需要队列进行判断。

思路:跟层次遍历一样,需要通过反复的取出结点并放入子结点,但不同的是,除非结点为空,否则其左右结点都需要放入队列。当取出到空结点的时候便不再进行取放操作,然后判断队列元素是否全为空,如果为空则是完全二叉树,如果不为空就不是完全二叉树。

注意:在返回false的时候也需要销毁队列。

2. oj题

2.1 单值二叉树

思路:如果根结点的左右子树与根结点的值相同,那么左右子树就可以单独再与其左右子树进行判断,进行递归。

注意:当递归到空结点的时候,这个时候返回true,因为空结点不影响结果。

如果遇到一个不相同的值便可以返回false了,最后将根结点的左右子树结果进行&&操作,只有两个子树都为true时这棵树才是单值二叉树。

代码如下:

2.2 检查两颗二叉树是否相同

思路:判断两个二叉树的头结点是否相同,如果相同则进行左右子树递归,不同则返回false,相同则不管,最后当空结点的时候返回true。

注意:当两颗二叉树都为空,是相同二叉树,当只有其中一颗为空时则不相同。

代码如下:

2.3 轴对称树

思路:可以借助上一题实现的相同树,只需要稍微修改,即将根结点的左子树与右子树进行判断是否相等。

代码如下:

2.4 另一棵树的子树

思路:还是借助相同树。从头结点开始判断两棵树是否相同,然后遍历所有结点,只要有一颗树相同就行。

注意:递归的时候return是使用 || 。

代码如下:

2.5 二叉树的构建即遍历

思路:通过递归进行构建二叉树。因为给先序遍历,即“根左右”。因此第一个是根结点,第二个是根结点的左结点,也是左子树的根结点。如果再读到一个不为空的值,那肯定是第二个结点的左结点,依次下去。直到读到两个为空的符号时这个结点便结束了,返回这个结点的根结点,再进行该根结点的右子树的创建,但是需要注意根结点的创建也是从左子树开始创建的。当读到一个为空的符号时,代表该结点的左子树结束,创建该结点的右子树。

因此递归的终止条件是读到为空的符号。

代码如下:

#include <stdio.h>

#include <stdlib.h>

//1.

typedef char btdatatype;

typedef struct btnode{

    struct btnode * left ;

    struct btnode* right;

    btdatatype val;

}btnode;

btnode * buynode(char x)

{

    btnode * newnode = (btnode *)malloc(sizeof(btnode));

    newnode->val =x;

    newnode->left = newnode->right = NULL;

    return newnode;

}

btnode * create(char * arr,int * pi)

{

    if(arr[*pi]=='#')

    {++(*pi);

        return NULL;}

    btnode * root = buynode(arr[*pi]);

    ++(*pi);

   root->left =  create(arr,pi);

   root->right= create(arr,pi);

   return root;

}

void inorder(btnode * root)

{

    if(root==NULL)

    return ;

    inorder(root->left);

    printf("%c ",root->val);

    inorder(root->right);


 

}

int main() {

   char arr[100];

   scanf("%s ",arr);

   int i =0;

   btnode * root = create(arr,&i);

   inorder(root);

    return 0;

}

具体实现的时候需要申请结点以及进行中序遍历,中序遍历比较简单,这里就不讲了。

3.源码

二叉树的实现以及判断完全二叉树,层次遍历 · a36cc5b · 重邮阿江/c_study_experience - Gitee.com二叉树oj题 · 7452d90 · 重邮阿江/c_study_experience - Gitee.com

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值