数据结构与算法--二叉树基础(上)

什么是树

在这里插入图片描述
树这种结构很像我们生活中的树,这里的每个元素叫做节点,用线连接的节点,我们叫做父子关系
比如下面这个图,A节点就是B节点的父节点,B节点是A节点的子节点,BCD三个节点的父节点是同一个父节点,他们互相称为兄弟节点,我们把没有父节点的称为根节点,比如E,我们把没有子节点的叫做叶子节点或叶节点比如图中的G H I J K L都是叶子节点
在这里插入图片描述
树还有几个相似的概念,高度,深度,层,他们的定义是这样的
节点的高度=节点到叶子节点的最长路径(边数)
节点的深度=根节点到这个节点经历边的个数
节点的层数=节点的深度+1
树的高度=根节点的高度
例如:
在这里插入图片描述
高度一般是从下向上计算,深度是从上到下计算,层数跟深度的计算相似,不过计数起点为1

二叉树

二叉树顾名思义,每个节点最多有俩个叉,分别是左子节点右子节点,二叉树不要求每个节点都有俩个叉,可以只有一个左子节点,也可以只有一个右子节点
在这里插入图片描述
上面这张图中有来个节点比较特殊,分别是2和3号

编号2的二叉树,叶子节点都在最底层,除了叶子节点之外,其他节点都有俩个叉,这种二叉树叫做满二叉树

编号3的二叉树,叶子节点在最下俩层,左后一层的叶子节点都靠左排列,并且除了最后一层,其它层节点个数都要达到最大,这种叫做完全二叉树
在这里插入图片描述

如何储存二叉树

储存二叉树有俩种方法,一是基于指针和引用的二叉链式储存法,一种是基于数组的顺序储存法

1 二叉链式储存法
这个比较简单,我们从图中可以看出,每个节点除了储存数据,还储存了左右子节点的指针,我们只要拿到根节点,就可以把整个树串起来
在这里插入图片描述顺序储存法
我们把根节点储存在下标i=1的位置,那么左子节点储存在下标2 * i = 2的位置,右子节点储存在下标2 * i + 1 = 3的位置,由此类推,B的左子节点储存在2 * i = 2 * 2 = 4的位置,B的右子节点储存在2 * i + 1 = 2 * 2 + 1 = 5的位置
在这里插入图片描述
总结一下 ,如果X储存在i位置,那么左子节点储存在i2的位置,右子节点储存在2i+1的位置,反过来i/2就是他父节点的位置,这种情况我们只要知道根节点的位置(一般根节点储存在下标1的位置,方便计算),就可以串起整个树

上方的例子是一个完全二叉树,所以只浪费了一个0的位置,不过如果不是完全二叉树,就会浪费比较多的空间
在这里插入图片描述
所以完全二叉树,做好的储存方式就是数组,因为数组不需要储存左右子节点的引用,这也是为什么完全二叉树会单独提出来,也是为什么完全二叉树最后一层叶子节点要靠左边的原因

二叉树的遍历

二叉树有三种遍历方式,前序遍历中序遍历后续遍历

前序遍历:对于树中任意节点来说,先打印这个节点,然后打印他的左子节点,最后打印他的右子节点

中序遍历:对于树中任一节点来说,先打印他的左子节点,然后打印他本身,最后打印他的右子节点

后序遍历:对于树中的任意节点来说,先打印他的左子节点,然后打印他的右子节点,最后打印它本身

在这里插入图片描述
实际上,二叉树的前中后遍历就是一个递归的过程,写递归代码的关键在于,是否可以写出递归公式

前序遍历的递推公式:
preOrder(r) = print r->preOrder(r->left)->preOrder(r->right)

中序遍历的递推公式:
inOrder(r) = inOrder(r->left)->print r->inOrder(r->right)

后序遍历的递推公式:
postOrder(r) = postOrder(r->left)->postOrder(r->right)->print r

翻译成代码

void preOrder(Node* root) {
  if (root == null) return;
  print root // 此处为伪代码,表示打印 root 节点
  preOrder(root->left);
  preOrder(root->right);
}

void inOrder(Node* root) {
  if (root == null) return;
  inOrder(root->left);
  print root // 此处为伪代码,表示打印 root 节点
  inOrder(root->right);
}

void postOrder(Node* root) {
  if (root == null) return;
  postOrder(root->left);
  postOrder(root->right);
  print root // 此处为伪代码,表示打印 root 节点
}

二叉树遍历的时间复杂度
从上边的图中可以看到,每个节点被访问了俩次,所有时间复杂度伪O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值