数据结构与算法篇 二叉树(Binary Tree)(一)

好多天没有写过数据结构和算法了,好了今天抽出点时间二叉树,前面讲到的都是线性表,栈,队列等等。

今天讲到的是非线性表结构--树,首先说一下什么是树的概念

树的这种数据结果挺像我们现实中的树,这里的每一个元素我们叫做节点,用线把相邻的节点连接起来,然后它们就成了父子关系。

A节点是B节点的父节点,B节点是A节点的子节点,BCD三个节点的父节点是同一个节点,所以它们之间称为兄弟节点,我们把

没有父节点的节点称为根节点,也就是E;没有子节点的节点称为叶子节点,其中GHIJKL都是

其中树还有三个相似的概念:高度,深度,层

换一种表达方式就是,高度相当于你从一楼开始往上数,这层楼有多高;深度就相当于你从水面测水底的深度,不同位置的深度都不一样;

接下来讲一下二叉树,二叉树顾名思义就是每一个节点都有两个叉,也就是有两个子节点,当然不强制要求有两个节点

其中还有两个关于二叉树的概念就是满二叉树和完全二叉树

满二叉树很好的理解,就是图中第二个,就是所有满了。。。

然而完全二叉树呢?是图中第三个,完全二叉树的概念是,叶子节点都在最底下两层,最后一层的·子节点靠左排列,并且除了最后一层其他层的节点数都要达到最大。

为什么要定义这么一颗树?我们慢慢来。。。。。。。

下面我们来看一下怎么存储一颗二叉树,有两种方法,第一种是基于指针或者引用的二叉链式存储,另外一种是基于数组的顺序存储法。

首先我们先来看一下链式存储,我们可以看出一个节点有三个部分组成,第一个是存储的数据,第二三个是左右节点的指针,然后就把整棵树串联起来了

接下来我们再看一下数组的顺序存储方式,如果节点x存储在数组中下标为i的位置,下标为2*i的存储的左子节点,下标为2*i+1的位置存储的是右子节点,i/2位置就是根节点,为了方便计算我们一般把根节点取为1。

讲到这里我们可以回想一下为什么有完全二叉树的出现了,一个完全二叉树,它只会浪费1个位置的存储位,如果是一颗非完全二叉树我们就浪费了大量的位置了,所以如果某课树是完全二叉树那么数组就是最节省存储的方式了

接下来讲一个我经常在面试的题目讲到的一个概念了,就是二叉树的遍历,经典的遍历方法有三种分别是前序遍历,中序遍历,后续遍历,一开始我经常忘记了这个死鬼概念,老是错了。背了又忘记了,真是日了哈士奇。

下面我们来认真看一下这三个概念

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

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

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

实际上,前中后三种遍历都是一个递归的过程,那么递归代码应该怎么去写,如果要解决问题A,那么子问题B,C必须解决了

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 节点
}

猜你喜欢

转载自blog.csdn.net/weixin_38452632/article/details/84073095