今天给大家说一下二叉树的实现,这个使用c语言写的,话不多说,先看看代码:
#pragma once
#include
#include
#include
typedef int type;
typedef struct tree
{
//数据域
type val;
//左孩子指针
struct tree* left;
//右孩子指针
struct tree* right;
}tree;
//创建二叉树
void creat(tree** root);
//二叉树的高度
int high(tree** root);
//二叉树的左右孩子交换
void swap(tree** root);
//前序遍历
void printfront(tree* root);
//中序遍历
void printmid(tree* root);
//后序遍历
void printback(tree* root);
//叶子结点
int leafnode(tree* root);
//单分支节点
int onenode(tree* root);
//总结点
int sumnode(tree* root);
#define _CRT_SECURE_NO_WARNINGS 1
#include "tree.h"
//创建二叉树
void creat(tree** root)
{
assert(root);
int ret = 0;
printf("是否要生成左孩子或是右孩子0,1->\n");
scanf("%d", &ret);
if (0 == ret)
{
*root = NULL;
printf("取消生成左孩子或是右孩子\n");
return;
}
else
{
tree* tem = (tree*)malloc(sizeof(tree));
assert(tem);
*root = tem;
printf("请输入你要保存的值->:\n");
scanf("%d", &((*root)->val));
creat(&(*root)->left);
creat(&(*root)->right);
}
}
//二叉树的高度
int high(tree** root)
{
if (*root == NULL)
return 0;
else
{
int left = high(&(*root)->left);
int right = high(&(*root)->right);
if (left > right)
return left + 1;
else if (right > left)
return right + 1;
else
return left + 1;
}
}
//交换二叉树的左右子树
void swap(tree** root)
{
if (*root == NULL)
return;
else
{
tree* node = (*root)->left;
(*root)->left = (*root)->right;
(*root)->right = node;
swap(&(*root)->left);
swap(&(*root)->right);
}
}
//前序遍历
void printfront(tree* root)
{
if (root == NULL)
return;
else
{
printf("%d->", root->val);
printfront(root->left);
printfront(root->right);
}
}
//二叉树的中序遍历
void printmid(tree* root)
{
if (root == NULL)
return;
else
{
printmid(root->left);
printf("%d->", root->val);
printmid(root->right);
}
}
//二叉树的后序遍历
void printback(tree* root)
{
if (root == NULL)
return;
else
{
printback(root->left);
printback(root->right);
printf("%d->", root->val);
}
}
//计算二叉树的叶子结点
int leafnode(tree* root)
{
if (root == NULL)
return 0;
else if (root->left == root->right)
return 1;
else
{
int left = leafnode(root->left);
int right = leafnode(root->right);
return left + right;
}
}
//计算单分支节点的个数
int onenode(tree* root)
{
if (root == NULL)
return 0;
else if (root->left == NULL && root->right != NULL)
return 1;
else if (root->right == NULL && root->left != NULL)
return 1;
else
{
int left = onenode(root->left);
int right = onenode(root->right);
return left + right;
}
}
//计算二叉树的总结点数
int sumnode(tree* root)
{
if (root == NULL)
return 0;
else
{
int left = sumnode(root->left);
int right = sumnode(root->right);
return left + right + 1;
}
}
#define _CRT_SECURE_NO_WARNINGS 1
#include "tree.h"
void test1()
{
tree* root;
//创建二叉树
creat(&root);
//二叉树的高度
printf("二叉树的高度:");
int treehigh=high(&root);
printf("%d\n",treehigh);
//二叉树的前序遍历
printf("二叉树的前序遍历:");
printfront(root);
printf("\n");
//二叉树的左右子树交换
printf("二叉树左右子树的交换:");
swap(&root);
printf("\n");
//二叉树的前序遍历
printf("二叉树的前序遍历:");
printfront(root);
printf("\n");
//二叉树的中序遍历
printf("二叉树的中序遍历:");
printmid(root);
printf("\n");
//二叉树的后序遍历
printf("二叉树的后序遍历:");
printback(root);
printf("\n");
//二叉树的总结点数
printf("二叉树的总结点数:");
int sum = sumnode(root);
printf("%d\n", sum);
//二叉树的叶子结点数
printf("二叉树的叶子节点数:");
int leaf = leafnode(root);
printf("%d\n", leaf);
//二叉树的单分支节点
printf("二叉树的单分支节点:");
int one = onenode(root);
printf("%d\n", one);
}
int main()
{
test1();
return 0;
}
老样子,写的比较正规一些,用了三个文件来实现的,就不详细说了。
先是头文件,相信学完c的你们很快就能看懂吧,这里就不详细说了,先看看tree.c这个文件,这个文件我是用来实现函数的,而test.c是测试的。所以,这里也不用多说了吧!
来说一下代码思路以及讲解吧!首先,要写二叉树的话必不可少的是要知道二叉树的存储结构,他是一个非线性的结构,但是我们可以根据图来看,很容易就能理解的是二叉树像是一种递归的结构,所以创建他的时候我们就用递归来创建,首先,先创建一个二叉树节点的指针,使他指向是这个二叉树的根节点,此时我们就可以创建了,因为是递归性质,所以我们不能无限的递归下去,要有限制条件,而且使他越来越接近这个递归条件,所以我用了ret这个变量来控制他的递归,选择条件是0或1,1是继续生成,0则是取消。
其次,这里要注意的是,我没有专门处理ret,所以只要你的选择是非0的数,都可以生成左右孩子,如果生成孩子的话,就很简单了,我们就申请空间,判断(这里说一下,因为个人感觉用if语句判断是否申请成功感觉很麻烦,所以直接断言,如果没有成功的话就直接退出程序)是否申请成功,然后分别把他的左右指针域用递归来继续生成。
第二,二叉树的遍历分为两大类,一种是递归,一种用队列来遍历,这里队列的遍历没有写,大家可以自己写一下,(很简单,需要先实现一个队列),递归的话就比较简单了,分为前序,中序,后序。前序:先是访问根节点,在左子树,最后是右子树,中序:左,根,右。后序:左,右,根。这个就很简单,这里也不再详细说。看代码就懂了。
剩下的就是计算树的高度了,这个其实很简单,脑海中想象出一颗树,先算左子树的高度,再算右子树的高度,最后比较左右子树的高度,然后让高的那个子树+1,就可以了。这里的+1是加上根节点的高度。
然后是交换左右子树,这个也比较简单,就是判断这个树是否为空,如果是空树的话就直接结束,否则交换左右子树,需要一个变量,就和两个数的交换是一样的道理,然后递归。
叶子结点的思路也很简单,就是左右指针的指向都是NULL就好了,但是这个里我写的是左右指针相等,其实原理相同,都是一样。没有什么区别。
单分支节点,个人感觉思路和算叶子结点的思路很像 ,要么左指针为空,右指针不空,要么右指针为空,左指针不空的话就返回1,然后递归接好了
计算总结点数,也是一样的道理,这里就不多说。
下面要说的是一个我个人认为困惑了我很久的知识点,那就是二叉树的交换,为什么可以交换呢?我其实刚开始有点懵,困惑了我很长时间,我在网上也搜了很多,有的人说是二叉树中不全是有序的,但是我还是不理解,因为二叉树的一个概念就是左右孩子是有次序的,不能颠倒。后来我也问了我的一个老师,他的回答让我拨云见日,他说如果换了,就不是同一个二叉树了。我也仔细想了一下。觉得他说的很详细,而我对这个的理解是这样的,同一个二叉树中,是不能交换的,如果硬要换,那么他就会形成一个新的二叉树,跟原来的二叉树不一样。这个一定要注意。
其次就是前中后序遍历中,不一定要用打印函数把这个值打印出来,他可以做很多的操作,比如线索话二叉树的时候,可以进行线索化的操作,也可以进行找前驱节点,所以,这里要灵活一些。
然后就是在创建二叉树的时候,我把左右指针赋值为NULL的操作写到了当你选择不生成孩子的时候那个里面,这是因为,如果你写到了你选生成孩子的那个里面的时候,你要用递归去生成左孩子或右孩子的时候,在给函数传参的时候,会有对空指针的解引用,所以,一定要写到Ret==0的那个里面。
以上就是个人对二叉树的理解,有不足之处希望大家可以指出,希望大家支持,谢谢!!!!!