1.从二分查找到树
举一个简单的例子:
有一条电话线连接着北京,天津,济南,南京,上海 ;从北京往上海打电话,打不通;怎么找到出问题的基站?
我们就可以直接从两端中心的城市向两端致电,济南打电话到北京,从济南打电话到上海;
哪一段不通,问题就出在哪一段;
再从此段开始(比如说是济南到上海段出问题),南京向济南打电话,南京向上海打电话,找出出问题的一段后,我们就找到了出问题的基站。
像如上的分层次查找出问题的思想就大大减少了我们逐一比对排查的时间
这也就是二分查找的主要思想,我们来看一段代码:
#include <stdio.h>
#define MAXSIZE 100
#define NotFound -1
typedef int ElementType;
/* 定义静态表结构体 */
typedef struct {
ElementType Element[MAXSIZE]; /* 元素数组 */
int Length; /* 表的长度 */
} StaticTable;
/* 二分查找函数 */
int BinarySearch(StaticTable *Tbl, ElementType K) {
int left, right, mid;
left = 0; /* 初始左边界 */
right = Tbl->Length - 1; /* 初始右边界 */
while (left <= right) {
mid = (left + right) / 2; /* 计算中间元素下标 */
if (K < Tbl->Element[mid]) {
right = mid - 1; /* 调整右边界 */
} else if (K > Tbl->Element[mid]) {
left = mid + 1; /* 调整左边界 */
} else {
return mid; /* 查找成功,返回元素下标 */
}
}
return NotFound; /* 查找不成功,返回-1 */
}
int main() {
StaticTable Tbl;
Tbl.Length = 10; /* 假设表长度为10 */
/* 初始化表中的元素(必须是有序的) */
int i;
for (i = 0; i < Tbl.Length; i++) {
Tbl.Element[i] = i * 2; /* 例如,表中存储0, 2, 4, 6, 8, 10, 12, 14, 16, 18 */
}
ElementType K = 16; /* 要查找的元素 */
int result = BinarySearch(&Tbl, K); /* 执行二分查找 */
if (result != NotFound) {
printf("元素 %d 在表中的下标是 %d\n", K, result); /* 打印查找结果 */
} else {
printf("元素 %d 未在表中找到\n", K); /* 打印查找失败 */
}
return 0;
}
我们图示一下这个程序的过程:
将每一层的mid“拎”起来后我们可以将所有的元素看成这样一种结构:
像分层次的组织在管理上具有更高的效率。
我们称这种数据的组织结构为“树”。
2.树的定义
树(Tree): n(n≥0)个结点构成的有限集合。
当n=0时,称为空树;
对于任一棵非空树(n> 0),它具备以下性质:
树中有一个称为“根(Root)”的特殊结点,用 r 表示;
其余结点可分为m(m>0)个互不相交的有限集T1,T2,... ,Tm,其 中每个集合本身又是一棵树,称为原来树的“子树(SubTree)”
3.树的基本术语
1. 结点的度(Degree):结点的子树个数
2. 树的度:树的所有结点中最大的度数
3. 叶结点(Leaf):度为0的结点
4. 父结点(Parent):有子树的结点是其子树 的根结点的父结点
5. 子结点(Child):若A结点是B结点的父结 点,则称B结点是A结点的子结点;子结点也 称孩子结点。
6. 兄弟结点(Sibling):具有同一父结点的各 结点彼此是兄弟结点。
7. 路径和路径长度:从结点n1到nk的路径为一 个结点序列n1 , n2 ,… , nk , ni是 ni+1的父结 点。路径所包含边的个数为路径的长度。【从上往下】
8. 祖先结点(Ancestor):沿树根到某一结点路 径上的所有结点都是这个结点的祖先结点。
9. 子孙结点(Descendant):某一结点的子树 中的所有结点是这个结点的子孙。
10. 结点的层次(Level):规定根结点在1层, 其它任一结点的层数是其父结点的层数加1。
11. 树的深度(Depth):树中所有结点中的最 大层次是这棵树的深度。
12.结点的深度和高度:结点的深度是从根节点开始自顶向下逐层累加的;【从上往下】
结点的高度是从叶节点开始自底向上逐层累加的 。【从下往上】
13.森林:森林是m(m>=0)棵互不相交的树的集合。把树的根结点删去就成了森林;反之,将m棵独立的树加上一个根结点,并把这m棵树作为该结点的子树,则森林就变成了树。
4.树的结构特点
(1)子树是不相交的;
(2)除了根结点外,每个结点有且仅有一个父结点;
(3)一棵N个结点的树有N-1条边。
(4)树中的结点数等于所有结点的度数之和加1;
(5)度为m的树中第i层至多有m^(i-1)个结点(i>=1);
(6)高度为h的m叉树至多有(m^h-1)/(m-1)个结点;
(7) 具有n个结点的m叉树的最小高度为[ logm( n(m-1) + 1 )];
5.树的表示
对于这棵树,假如每个结点都定义多个指针域来指向其儿子结点,势必会浪费调很多指针域。所有我们会采用以下的方法,也就是只定义两个指针域的方式。
儿子兄弟表示法
将上图倾斜45度,看看
是不是像二叉树?