二叉树的基本操作

这篇博客介绍了二叉树的基本概念,包括结点、度、深度等,并通过代码展示了如何创建二叉树,实现了二叉树的先序、中序、后序遍历,同时提供了计算二叉树结点数、叶子结点数和第K层叶子结点数的函数。通过递归思想解决二叉树问题。
摘要由CSDN通过智能技术生成

 在学习数据结构的时候学完栈、队列之后下一个比较难、比较重要的就是树。它是由n(n>=1)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:每个节点有零个或多个子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。

这是百度的一个词条介绍,一点都不通俗易懂

 

这就是一个抽象出来的通俗易懂的树的结构图,不过这是一种特殊的树的结构,也是今天我所要操作的树-------二叉树。其实二叉树很好理解,二叉树的每个结点至多只有二棵子树(不存在度大于2的结点)

这是一些树的相关术语,如果之前没听过树的话,可以简单了解一下

树的结点:包含一个数据元素及若干指向子树的分支;

孩子结点:结点的子树的根称为该结点的孩子;

双亲结点:B 结点是A 结点的孩子,则A结点是B 结点的双亲;

兄弟结点:同一双亲的孩子结点;

祖先结点: 从根到该结点的所经分支上的所有结点子孙结点:以某结点为根的子树中任一结点都称为该结点的子孙

树的深度:树中最大的结点层

树的度: 树中最大的结点度。

叶子结点:也叫终端结点,是度为 0 的结点;

对这些概念有一个简单的了解就可以。

今天我们就来通过代码创建一个二叉树。今天主要实现的函数有,二叉树的创建,二叉树的三种遍历方式,二叉树的中的结点个数,二叉树中叶子节点的个数,二叉树第K层的叶子结点个数。

首先我们先通过画图软件来画出我们今天要实现的二叉树的抽象图。

 

然后将他转化成一个数组int a[] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6, '#', '#', '#' };

这是这个二叉树先序遍历的数组,如果下边没有结点是空的话,那就用 '#'来表示。

 

typedef int BTDataType;

 

typedef struct BinaryTreeNode

{

struct BinaryTreeNode* _left;

struct BinaryTreeNode* _right;

BTDataType _data;

}BTNode;

 

 

BTNode* BuyBTNode(BTDataType x)

{

BTNode *Node =(BTNode*) malloc(sizeof(BTNode));

Node->_data = x;

Node->_left = NULL;

Node->_right = NULL;

return Node;

}

这是在创建二叉树之前的创建的二叉树结构体,以及给二叉树的空间分配函数。二叉树中包括你的左孩子指针,右孩子指针,以及你当前结点的数值。

 

BTNode* CreateBTree(BTDataType* a, size_t* pIndex, BTDataType invalid)

{

assert(a);

if (a[*pIndex] == invalid)

return NULL;

BTNode *root = BuyBTNode(a[*pIndex]);

++(*pIndex);

root->_left=CreateBTree(a, pIndex, invalid);

++(*pIndex);

root->_right=CreateBTree(a, pIndex, invalid);

return root;

 

 

}

之后是创建二叉树的函数,这里传入了三个参数,第一个是我们取值的数组,通过数组中的值来个二叉树中的结点赋值,pIndex是来访问的数组下标位置,正常的话我们这里传入一个数字就行,为什么要传入一个指针呢?因为看我们的程序,如果你传入的是一个数值。

root->_left=CreateBTree(a, Index++, invalid);这里写成这样,想一下,递归有什么特点?递归是在栈上进行的,栈大家也都清楚,在你当前函数运行结束之后,栈是会进行销毁的,但是你的数组可以一直进行下去的,通过图和数组对比也可以看到1的右孩子5的数组下标已经是8了。有的人说可以将你的index设置成全局或者说静态变量,这种方法在当前阶段也是可取的,但是当你存在多线程的时候全局变量就很容易受到其他线程的影响,导致程序出现一些bug所以这里我们传了指针。第三个参数是invalld也就是非法制也就是你的二叉树的结束值,这里在当前状态下也是可以不传的,但是当前的结束值是'#'如果以后改动的话还是传入一个参数比较方便控制。

  这里创建二叉树的函数代码十分简单就是将你当前结点和你的左右孩子结点链接起来就可以了。通过递归来实现最后返回你当前的根节点。

void BTreePrevOrder(BTNode* root)

{

if (root == NULL)

return;

else

{

printf("%d", root->_data);

BTreePrevOrder(root->_left);

BTreePrevOrder(root->_right);

 

}

}

先序遍历和中序遍历以及后序遍历的代码只是顺序的区别,所以这里我就只介绍一个先序中序后序遍历分别是什么。

 

通过这个图来介绍,这里的先中后指的是你的根节点的顺序,也就是说,如果是先序遍历,你当前在2位置,那就直接输出2然后再去遍历他的左孩子,右孩子,也就是234,如果要是中序遍历也就是虽然你当前在2位置但是不输出当前数据,会先遍历他的左孩子,然后中序遍历根节点就在中间,之后才是右孩子,所以顺序会是324,如果要是后序遍历,代表着你当前的结点在最后边,也就是先遍历左孩子右孩子然后才是根节点,这里的顺序是342.

 

如果说这个图的先序遍历,那就是123456,遇到1输出,然后遍历他的左孩子,遇到2输出,然后遇到他的左孩子3输出,下边没孩子,然后返回2,去遍历2的右孩子遇到4输出,然后再返回2,之后开始遍历1的右孩子。

在简单介绍一下这个图的后序遍历,遇到1先不输出往他的左孩子走,走到2,2还有左孩子继续走,走到3,没有左右孩子,直接输出3,然后返回2继续不输出去遍历2的右孩子,4输出,然后返回2之后,再到1,1的右孩子还没有输出所以不能输出1,开始遍历1的右孩子5,因为5有左孩子那就遍历6输出6,返回5去遍历5的右孩子是空返回来,然后输出5,最后返回1输出。后序遍历的顺序就是342651

void BTreeInOrder(BTNode* root)//中序遍历

{

if (root == NULL)

return;

else

{

BTreeInOrder(root->_left);

printf("%d", root->_data);

BTreeInOrder(root->_right);

 

}

}

void BTreePostOrder(BTNode* root)//后序遍历

{

if (root == NULL)

return;

else

{

BTreePostOrder(root->_left);

BTreePostOrder(root->_right);

printf("%d", root->_data);

 

}

}

 

size_t BTreeSize(BTNode* root)

{

if (root == NULL)

return 0;

else

return 1 + BTreeSize(root->_left) + BTreeSize(root->_right);

}

这是用来求二叉树中结点的个数,其实二叉树的基本操作要掌握一个关键词那就是递归,二叉树中用递归来实现程序是一个很方便的。对于这个求节点数,也是一样的,你当前数的结点数就是你当前结点1,加上你的左孩子的结点数,加上你的右孩子的结点数,这个子问题不断的向下扩展,一直到root是空的时候开始返回。

size_t BTreeLeafSize(BTNode* root)

{

if (root == NULL)

return 0;

if ((root->_left== NULL) && (root->_right == NULL))

return 1;

return BTreeLeafSize(root->_left) + BTreeLeafSize(root->_right);

}

size_t BTreeKLevelSize(BTNode* root, size_t k)

{

if (root == NULL)

{

return 0;

}

if (k == 1)

{

return 1;

}

return BTreeKLevelSize(root->_left, k - 1) + BTreeKLevelSize(root->_right, k - 1);

}

这两个分别是当前树的叶子结点数,以及树第K层。同样还是递归思想来实现,你的结点是你左孩子的叶子结点个数加上右孩子的叶子结点可数,一直划分下去的子问题。

void TestBinaryTree()

{

int a[] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6, '#', '#', '#' };

size_t index = 0;

BTNode* tree = CreateBTree(a, &index, '#');

BTreePrevOrder(tree);

printf("\n");

BTreeInOrder(tree);

printf("\n");

BTreePostOrder(tree);

printf("\n");

 

printf("BTreeSize%d\n", BTreeSize(tree));

printf("BTreeLeafSize%d\n", BTreeLeafSize(tree));

printf("BTreeKLevelSize?%d\n", BTreeKLevelSize(tree, 2));

}

 


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉树是一种非常重要的数据结构,它的基本操作包括创建、销毁、遍历、查找等。下面是二叉树基本操作的实现方法: 1. 创建二叉树:通过前序遍历的数组构建二叉树,其中 '#' 表示空节点。具体实现方法可以参考引用中的 BinaryTreeCreate 函数。 2. 销毁二叉树:遍历二叉树,依次释放每个节点的内存空间。具体实现方法可以参考引用中的 BinaryTreeDestory 函数。 3. 遍历二叉树二叉树的遍历包括前序遍历、中序遍历、后序遍历和层序遍历。具体实现方法可以参考引用中的 BinaryTreePrevOrder、BinaryTreeInOrder、BinaryTreePostOrder 和 BinaryTreeLevelOrder 函数。 4. 查找二叉树节点:在二叉树中查找值为 x 的节点,具体实现方法可以参考引用中的 BinaryTreeFind 函数。 5. 计算二叉树节点个数:计算二叉树中节点的个数,具体实现方法可以参考引用[2]中的 BinaryTreeSize 函数。 6. 计算二叉树叶子节点个数:计算二叉树中叶子节点的个数,具体实现方法可以参考引用中的 BinaryTreeLeafSize 函数。 7. 计算二叉树第 k 层节点个数:计算二叉树中第 k 层节点的个数,具体实现方法可以参考引用中的 BinaryTreeLevelKSize 函数。 8. 判断二叉树是否是完全二叉树:判断二叉树是否是完全二叉树,具体实现方法可以参考引用中的 BinaryTreeComplete 函数。 9. 计算二叉树的深度:计算二叉树的深度,具体实现方法可以参考引用中的 BinaryTreeDeep 函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值