00.二叉树基本

基本概念

  • 结点:表示树中的元素。
  • 结点的度:拥有子结点的个数
  • 叶子:度为0的结点,也叫终端结点
  • 树的度:树中结点的最大的度
  • 结点的层次:根结点是第一层,它的孩子结点是第二层,依次类推。
  • 树的高度:最大层次数。

  • 二叉树:所有结点的度数不超过2的树。
  • 满二叉树:高度为h的二叉树恰好有2^h-1个结点时。
  • 完全二叉树:叶子结点只可能出现在最后一层或倒数第二层,每个非叶子结点要么有两个孩子结点,要么只有左孩子结点。

满二叉树

叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点

完全二叉树

叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大

2是满二叉树,3是完全二叉树

二叉树的存储

要理解完全二叉树定义的由来,需要先了解一棵二叉树的存储

想要存储一棵二叉树,有两种方法,一种是基于指针或者引用的二叉链式存储法,一种是基于数组的顺序存储法

链式存储法

图中应该可以很清楚地看到,每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。我们只要拎住根节点,就可以通过左右子节点的指针,把整棵树都串起来。

这种存储方式比较常用。大部分二叉树代码都是通过这种结构来实现的

基于数组的顺序存储法

把根节点存储在下标i = 1的位置,那左子节点存储在下标2 * i = 2的位置,右子节点存储在2 * i + 1 = 3的位置。
以此类推,B节点的左子节点存储在2 * i = 2 * 2 = 4的位置,右子节点存储在2 * i + 1 = 2 * 2 + 1 = 5的位置

如果节点X存储在数组中下标为i的位置,下标为2 * i 的位置存储的就是左子节点,下标为2 * i + 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

1个节点有左右子树,被分为3个点
递归的访问整棵树的时候都要访问这三个点

二叉树的前中后序遍历(递归方式)

posted @ 2020-10-20 23:35  H&K  阅读(382)  评论(0编辑  收藏  举报