初步学习二叉树

引入

在学习数组的时候相信很多人都学过,二分查找法,二分查找法的时间复杂度只有O(logn)(注:以2为地),但是二分查找法在生产实际中很少使用。原因它要有序,且要求是数组(空间连续)。一个数组4字节,如果十亿个数字排序就要大概4G的连续空间。所以在生产中一般使用哈希表,二叉搜索树等。

这两张图片相信很多人都见过,这就是现实的二叉树

树的概念与结构

特殊二叉树

满二叉数:每层节点都是满的,2^(h-1)

完全二叉树:由满二叉树引出的效率很高,除了最后一层最后一层,其余层也是满的

二叉树结构的一些名词

结点的度:一个结点含有的子树的个数称为该结点的度; 如上图:A的为6

叶结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I...等结点为叶结点

非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G...等结点为分支结点

双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点

兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点

树的度:一棵树中,最大的结点的度称为树的度; 如上图:树的度为6

结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;

树的高度或深度:树中结点的最大层次; 如上图:树的高度为4

堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点

结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先

子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙

森林:由m(m>0)棵互不相交的树的集合称为森林;

二叉树的一些性质

1.假设根节点为层数1,K层的二叉树(满二叉树)的节点最多为2^K-1

2.第i层的二叉树节点最多为2^(i-1)

(注:其实就是等比数列)

3.对于任意一个二叉树度尾0的节点个数和度尾2的节点关系为:N0 = N2+1

推导:设节点个数为N,二叉树的节点个数是由n0,n1,n2(度为0,1,2)组成的

所以得N=n0+n1+n2。引出树的边概念,树的边就是连接节点的那条线,数量是N-1。

叶节点没有边,也就是说n0(度为0的节点)的边为0,,度为一的产生一条边,度为二的产生两条边所以:N-1=n1+2*n2

两式结合n0=n2+1

4.若规定根结点的层数为1,具有n个结点的满二叉树的深度,h=log(n+1)

对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有结点从0开始编号,则对于序号为i的结点有(和堆一样):

双亲节点:若i > 0,双亲节点编号为(i-1)/2,0为根,无父节点

左孩子:若i < n,左孩子节点为2*i+1,如果2*i+1大于等于n则无孩子

右孩子:若i < n,右孩子节点为2*i+2,如果2*i+2大于等于n则无孩子

二叉树的存储结构

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。

1. 顺序存储

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储,二叉树的顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

2. 链式存储

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉数

二叉树的遍历

前序遍历(根左右)ABD000CE00F00,中序遍历(左根右)0D0B0A0E0C0F0,后序遍历(左右根)00D0B00E00FCA

注:我用0代表空

void PrevOrder(struct TreeNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	printf("%c ", root->val);
	PrevOrder(root->left);
    //中序就是把打印移到这
	PrevOrder(root->right);
    //后序是移到这
}

层序遍历(就是按从上至下从左至右顺序)

//需要用到队列,c语言没有队列的库,我自己造的轮子,所以发现编译器报错那可能是
//你没有写
void BinaryTreeLevelOrder(BTNode* root)
{
	Queue qu;
	BTNode * cur;

	QueueInit(&qu);

	QueuePush(&qu, root);

	while (!QueueIsEmpty(&qu))
	{
		cur = QueueTop(&qu);

		putchar(cur->_data);

		if (cur->_left)
		{
			QueuePush(&qu, cur->_left);
		}

		if (cur->_right)
		{
			QueuePush(&qu, cur->_right);
		}

		QueuePop(&qu);
	}

	QueueDestory(&qu);
}

习题练:

我会把题目和链接都给出来,题解在官网里有我就不给了

相同树:. - 力扣(LeetCode)

对称树:. - 力扣(LeetCode)

二叉树的前序遍历

另一棵树的子树

二叉树的中序遍历

二叉树遍历_牛客题霸_牛客网

好了,这篇文章是为了帮助我自己复习写的,可能有些知识并不详细。如果你无意看到我的文章,我也希望它对你有所帮助,文章不足之处也希望大家不吝赐教。最后,谢谢你的耐心阅读

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值