第四章 树与树的表示(四)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
线性时间复杂度T(n)=O(n)
72 30
49 9
43
38
结点数 最多交换次数 n/4 1 n/8 2 n/16 3 …… n/2k=1 log2n-1 (k-1)
n n n n T (n) 2 3 ... k (k 1) 4 8 16 2 n n n n 2T (n) 2 3 ... k 1 (k 1) 2 4 8 2 n n n n n 2T (n) T (n) ... k 1 k (k 1) n (log 2 n 1) n 2 4 8 2 2
分数段 比例 0-59 0.05 60-69 0.15 70-79 0.40 80-89 90-100 0.30 0.10
修改判定树:
yes score<80 no yes score<70 no yes score<60 no grade=1 grade=2 grade=3 yes score<90 no grade=4 grade=5
~O(1) ~O( n ) ~O( n ) ~ O(1) ~ O( n ) ~ O( 1 )
~ O( n ) 或 O(log2 n ) ~ O( n ) ~ O( 1 ) ~ O( n ) ~ O( 1 ) ~ O( 1 )
是否可以采用二叉树存储结构? 二叉搜索树? 如果采用二叉树结构,应更关注插入还是删除?
树结点顺序怎么安排?
树结构怎样?
优先队列的完全二叉树表示
a b d h a b c d i e f g h i e f c
g
0
1
2
3
4
5
6
ຫໍສະໝຸດ Baidu
7
8
9
10 11
堆的两个特性 结构性:用数组表示的完全二叉树; 有序性:任一结点的关键字是其子树所有结点的最大值(或最小值) “最大堆(MaxHeap)”,也称“大顶堆”:最大值 “最小堆(MinHeap)”,也称“小顶堆” :最小值
(3)最大堆的删除
取出根结点(最大值)元素,同时删除堆的一个结点。确定最后
一个结点的元素放到哪个结点中去是最大堆删除操作的关键所在。从根
结点开始,用最大堆中的最后一个元素向上过滤下层结点。
取出根结点元素58,要删除的结点应该是数组的最后一个单元 把 31 移至根,为了保持完全二叉树的结构特性,移去的是该结点。 要保持最大堆的性质,找出31的较大的孩子44上移。 空出的结点位置为存放删除结点元素31的正确位置。
[2] 25 18 [4] 10 [3] 31 20
[5] [6] 20 < 35 > 31 31 35 < 44
Case 1 : new_item = 20 Case 2 : new_item = 35
Case 3 : new_item = 58
58 >
31
58 >
44
58 < MaxData
4.6.2 哈夫曼树与哈夫曼编码
1.什么是哈夫曼树(Huffman Tree)
[例] 将百分制的考试成绩转换成五分制的成绩
if( score < 60 ) grade =1; else if( score < 70 ) grade =2; else if( score < 80 ) grade =3; else if( score < 90 ) grade =4; else grade =5; 判定树:
= 2.2
如何根据结点不同的查找频率构造更有效的搜索树?
从新增结点的父结点开始,用要插入的元素向下过滤上层结点
算法:将新增结点插入到从其父结点到根结点的有序序列中
void Insert( MaxHeap H, ElementType item ) { /* 将元素item 插入最大堆H,其中H->Elements[0]已经定义为哨兵 */ int i; if ( IsFull(H) ) { printf("最大堆已满"); return; } i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */ for ( ; H->Elements[i/2] < item; i/=2 ) H->Elements[i] = H->Elements[i/2]; /* 向下过滤结点 */ H->Elements[i] = item; /* 将item 插入 */ }
若采用数组或链表实现优先队列
数组 : 插入 — 元素总是插入尾部 删除 — 查找最大(或最小)关键字 从数组中删去需要移动元素 链表: 插入 — 元素总是插入链表的头部 删除 — 查找最大(或最小)关键字 删去结点 有序数组: 插入 — 找到合适的位置 移动元素并插入 删除 — 删去最后一个元素 有序链表: 插入 — 找到合适的位置 插入元素 删除 — 删除最后元素
yes grade=1 score<60 yes grade=2 no
score<70
yes
no
no no grade=5
score<80 yes
grade=3
score<90
grade=4
如果考虑学生成绩的分布的概率:
分数段 比例 0-59 0.05 60-69 0.15 70-79 0.40 80-89 90-100 0.30 0.10
if( score < 80 ) { if( score < 70 ) if( score < 60 ) grade =1; else grade = 2; }else if( score < 90 ) grade =4; else grade =5;
效率: 0.05× 3+0.15 ×3+0.4× 2+0.3 ×2+0.1× 2
ElementType DeleteMax( MaxHeap H ) { /* 从最大堆H中取出键值为最大的元素,并删除一个结点 */ int Parent, Child; ElementType MaxItem, temp; if ( IsEmpty(H) ) { printf("最大堆已为空"); return; } MaxItem = H->Elements[1]; /* 取出根结点最大值 */ /* 用最大堆中最后一个元素从根结点开始向上过滤下层结点 */ temp = H->Elements[H->Size--]; for( Parent=1; Parent*2<=H->Size; Parent=Child ) { Child = Parent * 2; if( (Child!= H->Size) && (H->Elements[Child] < H->Elements[Child+1]) ) Child++; /* Child指向左右子结点的较大者 */ if( temp >= H->Elements[Child] ) break; else /* 移动temp元素到下一层 */ H->Elements[Parent] = H->Elements[Child]; } H->Elements[Parent] = temp; return MaxItem; }
【例】最大堆和最小堆
56 19 40 10 18 9 3 49 18 38 33 21 16 5 30 19 17 30
注意:从根结点到任意结点路径上结点序列的有序性!
【例】不是堆
56 19 40 10 18 3 49 15 38 33 21 16 5 30 19 37 30
2.堆的抽象数据类型描述
类型名称:最大堆(MaxHeap) 数据对象集:完全二叉树,每个结点的元素值不小于其子结点的元素值 操作集:最大堆H∈MaxHeap,元素item ∈ ElementType,主要操作有: •MaxHeap Create( int MaxSize ):创建一个空的最大堆。 •Boolean IsFull( MaxHeap H ):判断最大堆H是否已满。 •Insert( MaxHeap H, ElementType item ):将元素item插入最大堆H。 •Boolean IsEmpty( MaxHeap H ):判断最大堆H是否为空。 •ElementType DeleteMax( MaxHeap H ):返回H中最大元素(高优先级)。
把MaxData换成 小于堆中所有元素的 MinData,同样适用于 创建最小堆。
MaxHeap Create( int MaxSize ) /* 创建容量为MaxSize的空的最大堆 */ { MaxHeap H = malloc( sizeof( struct HeapStruct ) ); H->Elements = malloc( (MaxSize+1) * sizeof(ElementType)); H->Size = 0; H->Capacity = MaxSize; H->Elements[0] = MaxData; /* 定义“哨兵”为大于堆中所有可能元素的值,便于以后更快操作 */ return H; }
(1)最大堆的操作
最大堆的创建
typedef struct HeapStruct *MaxHeap; struct HeapStruct { ElementType *Elements; /* 存储堆元素的数组 */ /* 堆的当前元素个数 */ int Size; /* 堆的最大容量 */ int Capacity; };
比交换数据要快
算法:将新增结点插入到从其父结点到根结点的有序序列中
void Insert( MaxHeap H, ElementType item ) { /* 将元素item 插入最大堆H,其中H->Elements[0]已经定义为哨兵 */ int i; H->Element[ 0 ] 是哨兵元素, if ( IsFull(H) ) { 它不小于堆中的最大元素, printf("最大堆已满"); 控制顺环结束。 return; } i = ++H->Size; /* i指向插入后堆中的最后一个元素的位置 */ for ( ; H->Elements[i/2] < item; i/=2 ) H->Elements[i] = H->Elements[i/2]; /* 向下过滤结点 */ H->Elements[i] = item; /* 将item 插入 */ } T (N) = O ( log N ) 哨兵: 1000 [0] 20[1] 15[3] 12[6] 8[13] 6[27]
4.6 树的应用
4.6.1 堆(heap)及其操作
“堆(Heap)”正是考虑了适合于特权需要的数据结构,因此,
堆也通常被称作为“优先队列”。
1.堆的定义和表示
优先队列(Priority Queue):特殊的“队列”,取出元素的 顺序是依照元素的优先权(关键字)大小,而不是元素进入队 列的先后顺序。 问题:如何组织优先队列? 一般的数组、链表? 有序的数组或者链表? 二叉搜索树? AVL树?
查找效率:0.05× 1+0.15 ×2+0.4× 3+0.3 ×4+0.1× 4
yes score<60 yes grade=2 no no no no grade=5
= 3.15
grade=1
score<70 yes
score<80 yes
grade=3
score<90
grade=4
如果考虑学生成绩的分布的概率:
(4)最大堆的建立
建立最大堆:将已经存在的N个元素按最大堆的要求存放在
一个一维数组中。
方法1:通过插入操作,将N个元素一个个相继插入到一个初 始为空的堆中去,其时间代价最大为O(N logN)。
方法2:在线性时间复杂度下建立最大堆。
(1)将N个元素按输入顺序存入,先满足完全二叉树的结构特性 (2)调整各结点位置,以满足最大堆的有序特性。
79
当前考虑结点 当前考虑结点 当前考虑结点
66
83 55 30 72 87 49 9
43 38
72 91 30
当前考虑结点 当前考虑结点 当前考虑结点
79 91 66 8391 8379 91 55 83 66 72 43 87 49 87 43 38
30
9
91 83 79 55 66 87