一. 为什么要设计树结构
- 树结构本身是一种天然的组织结构;
- 将数据使用树结构存储后,出奇的高效(二分搜索树,平衡二叉树中的AVL和红黑树,对数据某一类特殊操作的堆和并查集,某类特殊数据处理的线段树和Trie(字典树,前缀树))。
二. 二分搜索树(Binary Search Tree)
2.1 二叉树
二叉树的特点:
- 二叉树和链表一样是一种动态数据结构,不同的是二叉树的每个节点内是有两个指向其它节点的指针的
- 二叉树具有唯一的根节点,二叉树每个节点最多有两个孩子,最多有一个父亲节点
- 二叉树具有天然的递归结构,每个节点的左子树和右子树也分别都是一颗二叉树,换句话说就是每个节点都分别连接的两棵更小的二叉树
- 二叉树不一定是“满”的,一个节点甚至是 "null" 也可以是一棵二叉树
二叉树的性质:
- 二叉树中,度为2的节点和叶子节点个数的关系为:叶子节点个数=度为2的节点个数+1
- 在二叉树的第 i 层上至多有个节点()
- 深度为 k 的二叉树至多有个节点()
- 具有n个节点的完全二叉树的深度为
- 已知前序遍历和中序遍历或者已知后序遍历和中序遍历可以唯一确定一棵二叉树,而已知前序遍历和后序遍历无法唯一确定一棵二叉树
2.2 二分查找法
- 对于有序数列,才能使用二分查找法(排序算法的作用,将数列进行排序)
- 二分查找法的时间复杂度为O(logn).
- 可以通过非递归(迭代)和递归的方式实现,递归实现性能相对较差
// 非递归的二分查找算法
public class BinarySearch {
// 我们的算法类不允许产生任何实例
private BinarySearch() {}
// 二分查找法,在有序数组arr中,查找target
// 如果找到target,返回相应的索引index
// 如果没有找到target,返回-1
public static int find(Comparable[] arr, Comparable target) {
// 在arr[l...r]之中查找target
int l = 0, r = arr.length-1;
while( l <= r ){
//int mid = (l + r)/2;
// 防止极端情况下的整形溢出,使用下面的逻辑求出mid
int mid = l + (r-l)/2;
if( arr[mid].compareTo(target) == 0 )
return mid;
if( arr[mid].compareTo(target) > 0 )
r = mid - 1;
else
l = mid + 1;
}
return -1;
}
// 递归的二分查找算法
public class BinarySearch2 {
// 我们的算法类不允许产生任何实例
private BinarySearch2() {}
private static int find(Comparable[] arr, int l, int r, Comparable target){
if( l > r )
return -1;
//int mid = (l+r)/2;
// 防止极端情况下的整形溢出,使用下面的逻辑求出mid
int mid = l + (r-l)/2;
if( arr[mid].compareTo(target) == 0 )
return mid;
else if(