树_二叉树_学习记录

声明:该文章仅为我个人的学习记录,由于我只是个新手,因此有错误之处还请各位见谅!也恳请大家能积极提出建议!

二叉树

二叉树就是树形结构里比较特殊的一种,即每个结点最多只有左右两个子树,整棵树中不存在度>2的结点

二叉树的左右子树是有顺序的,即使只有一个子树,也得区分它到底是左子树还是右子树

二叉树的五种基本形态:

空树
只有根节点
只有根节点+左子树
只有根节点+右子树
根节点+左、右两个子树

满二叉树/完全二叉树/斜二叉树

满二叉树:顾名思义,一切都是满满当当的,所有叶子都在最后一层,而且每个子结点的度都为2,即每个子结点都拥有左右子树
同样的深度下,满二叉树的叶子和结点最多
在这里插入图片描述
完全二叉树的范围稍大,而且包含了满二叉树在内
注:满二叉树一定是完全二叉树,而完全二叉树不一定是满二叉树
完全二叉树的特点是,按从上到下,从左到右的顺序给结点编号的话,是不会出现空挡的,如果出现了,就不是完全二叉树了,
换种讲法就是,把最后一层剔除掉的话,完全二叉树就是满二叉树了,且最后一层的叶子集中在左边,秉持有左才能有右的概念,即如果存在度为1的结点,那这个结点的子树一定是左子树,不可能是右子树
同样的结点数下,完全二叉树的深度最低
在这里插入图片描述
斜二叉树:只有左子节点或只有右子节点的二叉树称为斜二叉树
斜二叉树的结点数 = 深度
在这里插入图片描述

性质

都是一些简单的关系式
(设叶子结点的个数为n0,度为1的结点数为n1,度为2的结点数为n2)
1:在二叉树的第x层中,结点最多为
2^(x-1)

2:在深度为x的二叉树里,结点的总和不会超过
(2^x)-1

3:二叉树的结点总数
n = n0 + n1 + n2

4:二叉树的总连接线
x = n - 1 = n1 + 2 * n2

(n - 1是因为每个结点都会有一条线指向双亲,只有根节点没有,所以x = n - 1)
(n1 + 2 * n2是因为每个结点的线也可以看作是结点指向他们的孩子的,这样根节点也算进去了,而叶子没有孩子,自然也没有指向孩子的线,度为1就有一根线,度为2就有两根线,所以x = n1 + 2 * n2)

5:由性质4可以得出n0 + n1 + n2 - 1 = n1 + 2 * n2
最后得到
n0 = n2 +1
即叶子数 = 度为2的结点数 + 1;

6:由性质2可得有n个结点的的完全二叉树的深度为
(log2 n)向下取整 + 1

7:在一颗结点数为n完全二叉树中,设i是各个结点的编号,且有1<= i <= n
当i = 1时,i所在的结点为根节点
当2i > n时,该结点要么是叶子,要么左孩子的编号是2i
当2i + 1 > n 时,该结点要么无右孩子,要么右孩子的编号是2i+1

二叉树的存储结构

顺序结构
一般用于完全二叉树,用于其他情况会造成空间的浪费

链式结构
二叉链表:每个结点除了数据域,还有两个指针域,用来指向左右孩子
也可以在增加一个指向双亲的指针域,可以叫三叉链表

二叉树的遍历

利用递归的形式,可以非常简洁的遍历二叉树,甚至只要改变一下访问语句于递归语句的顺序,就可以做到以前序,中序,后序的方式遍历整个二叉树,因此这里就不写了,写个迭代法吧

迭代遍历
说一下思路,递归遍历很简单是因为二叉树遍历本身就和递归的性质很像,对每一个结点的操作都是一样的,假如是前序遍历(中,左,右),先输出当前结点,然后跳转到左子节点,然后再次输出当前结点,再判断是否有左子结点…说着说着就变成递归了

我们用一个栈来模拟递归的过程,给出一个二叉树,我们先判断这树的根节点是不是空的,不是空的,就把根节点压入栈,然后用一个临时指针指向根节点,并且输出根节点数值的同时从栈中弹出这个结点,然后再利用临时指针判断这个结点是否有右子结点,有就入栈,再判断是否有左子结点,有就入栈,因为栈的特性,所以现在左子结点在栈顶,然后我们就可能开始循环了,再次输出栈顶结点的值,然后再将右,左子结点入栈,所以每次输出的时候都是输出左子结点,而右子结点则被挡在后面,直到没有左子结点为止,这就符合前序遍历的规则

前序:

vector<int> qianxu (treenode* head)
{
	vector<int> res;
	stack<treenode*>st;
	if(head) st.push(head);
	while(!st.empty())
	{
		treenode* p = st.top();
		st.pop();
		res.push_back(p->val);
//前序是要先左后右,但栈是先进后出,所以反过来入栈
		if(p->right)st.push(p->right);
		if((p->left))st.push(p->left);
	}
	return res;
}

中序:

vector<int> zhongxu(treenode* head)
{
	vector<int> res;
	stack<treenode*> st;
	treenode* p = head;
	while(p != nullptr || !st.empty())
	{
		if( p!= nullptr)
		{
//先是一路往左,把左结点全部入栈,然后再次往左,p == nullptr
			st.push(p);
			p = p->left;
		}
		else
		{
			p = st.top();
			st.pop();
			res.push_back(p->val);
			p = p->right;
		}
	}
	return res;
}

具体语句待补充

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

timathy33

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值