什么是树?
真实的树:

树的特点:
现实生活中很多结构都是树的抽象,模拟的树结构相当于旋转180°的树。

树结构对比于数组/链表/哈希表有哪些优势呢:
数组:
链表:
哈希表:
树结构:
优点:树结构综合了上述三种结构的优点,同时也弥补了它们存在的缺点(虽然效率不一定都比它们高),比如树结构中数据都是有序的,查找效率高;空间利用率高;并且可以快速获取最大值和最小值等。
总的来说:每种数据结构都有自己特定的应用场景
树结构:
对于任一棵非空树(n > 0),它具备以下性质:
树的常用术语:


如图,树结构的组成方式类似于链表,都是由一个个节点连接构成。不过,根据每个父节点子节点数量的不同,每一个父节点需要的引用数量也不同。比如节点A需要3个引用,分别指向子节点B,C,D;B节点需要2个引用,分别指向子节点E和F;K节点由于没有子节点,所以不需要引用。
这种方法缺点在于我们无法确定某一结点的引用数。

这种表示方法可以完整地记录每个节点的数据,比如:
//节点A
Node{
//存储数据
this.data = data
//统一只记录左边的子节点
this.leftChild = B
//统一只记录右边的第一个兄弟节点
this.rightSibling = null
}
//节点B
Node{
this.data = data
this.leftChild = E
this.rightSibling = C
}
//节点F
Node{
this.data = data
this.leftChild = null
this.rightSibling = null
}
这种表示法的优点在于每一个节点中引用的数量都是确定的。
以下为儿子-兄弟表示法组成的树结构:

将其顺时针旋转45°之后:

这样就成为了一棵二叉树,由此我们可以得出结论:任何树都可以通过二叉树进行模拟。但是这样父节点不是变了吗?其实,父节点的设置只是为了方便指向子节点,在代码实现中谁是父节点并没有关系,只要能正确找到对应节点即可。
二叉树的概念:如果树中的每一个节点最多只能由两个子节点,这样的树就称为二叉树;
二叉树十分重要,不仅仅是因为简单,更是因为几乎所有的树都可以表示成二叉树形式。
二叉树的组成:
二叉树的五种形态:

上图分别表示:空的二叉树、只有一个节点的二叉树、只有左子树TL的二叉树、只有右子树TR的二叉树和有左右两个子树的二叉树。
二叉树的特性:

完美二叉树
完美二叉树(Perfect Binary Tree)也成为满二叉树(Full Binary Tree),在二叉树中,除了最下一层的叶子节点外,每层节点都有2个子节点,这就构成了完美二叉树。

完全二叉树
完全二叉树(Complete Binary Tree):

在上图中,由于H缺失了右子节点,所以它不是完全二叉树。
常见的二叉树存储方式为数组和链表:
使用数组:

| 节点 | A | B | C | D | E | F | G | H |
|---|---|---|---|---|---|---|---|---|
| 序号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
使用数组存储时,取数据的时候也十分方便:左子节点的序号等于父节点序号 * 2,右子节点的序号等于父节点序号 * 2 + 1 。

| 节点 | A | B | C | ^ | ^ | F | ^ | ^ | ^ | ^ | ^ | ^ | M |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 序号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
使用链表
二叉树最常见的存储方式为链表:每一个节点封装成一个Node,Node中包含存储的数据、左节点的引用和右节点的引用。

二叉搜索树(BST,Binary Search Tree),也称为二叉排序树和二叉查找树。
二叉搜索树是一棵二叉树,可以为空;
如果不为空,则满足以下性质:

如上图所示,树二和树三符合3个条件属于二叉树,树一不满足条件3所以不是二叉树。
总结:二叉搜索树的特点主要是较小的值总是保存在左节点上,相对较大的值总是保存在右节点上。这种特点使得二叉搜索树的查询效率非常高,这也就是二叉搜索树中"搜索"的来源。
下面是一个二叉搜索树:

若想在其中查找数据10,只需要查找4次,查找效率非常高。

同样是15个数据,在排序好的数组中查询数据10,需要查询10次:

其实:如果是排序好的数组,可以通过二分查找:第一次找9,第二次找13,第三次找15…。我们发现如果把每次二分的数据拿出来以树的形式表示的话就是二叉搜索树。这就是数组二分法查找效率之所以高的原因。