第9章 优先队列(Priority Queues)

Slides:



Advertisements
Similar presentations
Author : Hyesook Lim, Changhoon Yim, and Earl E. Swartzlander, Jr., Fellow Publisher : IEEE TRANSACTIONS ON COMPUTERS, VOL. 59, NO. 6, JUNE 2010 Presenter.
Advertisements

算法分析(3) 重要的数据结构.
第7章 樹與二元樹 (Trees and Binary Trees)
引入树 线性表、堆栈和队列都是线性结构,它们的共同特点:一对一; 计算机对弈中的一个格局可能有多个后继格局,用线性结构难以描述。
第5章 树( Tree )和二叉树 5.1 树的基本概念 5.2 二叉树 5.3 遍历二叉树和线索二叉树 5.4 树和森林
資料結構與C++程式設計進階 資料結構概論 講師:林業峻 CSIE, NTU 6/ 7, 2010.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
Minimum Spanning Trees
§4 Additional Binary Tree Operations
Chap4 Tree.
Tree(樹) 什麼是「樹」? 「樹」的範例 「樹」的定義 「樹」的表示法.
Chapter 5 Tree & Binary Tree
Hadoop I/O By ShiChaojie.
樹狀結構 陳怡芬 2018/11/16 北一女中資訊專題研究.
第九章 排序 概述 插入排序 交换排序 选择排序 归并排序 基数排序 外排序.
Chapter8 Binary and Other Trees
講師:郭育倫 第3章 基本資料結構 講師:郭育倫
Chapter9 Priority Trees
Chap 3 堆疊與佇列 Stack and Queue.
Chapter 6 Graph Chang Chi-Chung
强连通分量 无向图 1、任意两顶点连通称该图为连通图 2、否则将其中的极大连通子图称为连通分量 A D C B E 有向图
第七章 搜索结构 静态搜索结构 二叉搜索树 AVL树.
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
哈夫曼编码.
第12章 樹狀搜尋結構 (Search Trees)
辅导课程六.
Lexicographical order VS canonical order
Chapter 6 队列(QUEUES).
第 七 章 樹狀結構 課程名稱:資料結構 授課老師:________ 2019/1/1.
第11讲 树和二叉树(二).
第六章 树与森林 树和森林的概念 二叉树 (Binary Tree) 二叉树的表示
樹狀結構 Tree Structure chapter 7 德明科技大學資訊科技系.
动态规划(Dynamic Programming)
Data Structure.
二叉树和其他树 (Binary and other trees)
第六章 樹狀結構 T r e e 版權屬作者所有,非經作者 同意不得用於教學以外用途.
樹 2 Michael Tsai 2013/3/26.
感謝同學們在加分題建議. 我會好好研讀+反省~
Chapter6 队列(Queues) The Abstract Data Type
Tree & Binary Tree.
无向树和根树.
二叉树的遍历.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
Reference to FUNDAMENTALS OF DATA STRUCTURE IN C++
顺序表的删除.
第8章 資料排序 資料結構設計與C++程式應用
线 性 代 数 厦门大学线性代数教学组 2019年4月24日6时8分 / 45.
第九章 排序 概述 插入排序 快速排序 交换排序(起泡排序) 选择排序 归并排序.
第7章 樹與二元樹(Trees and Binary Trees)
分裂对象模型 C++ otcl.
Lightweight Data-flow Analysis for Execution-driven Constraint Solving
iSIGHT 基本培训 使用 Excel的栅栏问题
计算机问题求解 – 论题1-5 - 数据与数据结构 2018年10月16日.
3.16 枚举算法及其程序实现 ——数组的作用.
累堆排序法 (Heap Sort).
树和图 tree and graph 蔡亚星.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
唐常杰 四川大学计算机学院 计算机科学技术系
十二、堆 堆的定义.
#define RBTREE_RED 0 #define RBTREE_BLACK 1 typedef int dataType; typedef struct treeNode{ dataType key; int color; //red:0.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
Data Structure.
插入排序的正确性证明 以及各种改进方法.
第10章 二元搜尋樹 (Binary Search Tree)
§4.5 最大公因式的矩阵求法( Ⅱ ).
本节内容 1. 平衡二叉树的定义 2.平衡化旋转 3.平衡二叉排序树的插入操作 昆山爱达人信息技术有限公司
最小生成树 最优二叉树.
§2 自由代数 定义19.7:设X是集合,G是一个T-代数,为X到G的函数,若对每个T-代数A和X到A的函数,都存在唯一的G到A的同态映射,使得=,则称G(更严格的说是(G,))是生成集X上的自由T-代数。X中的元素称为生成元。 A变, 变 变, 也变 对给定的 和A,是唯一的.
JAVA 程式設計與資料結構 第十七章 Tree.
Presentation transcript:

第9章 优先队列(Priority Queues)

本章内容 9.1 引言 9.2 线性表 9.3 堆 9.4 左高树 9.5 应用

Bird’s Eye View Unlike the queues, which are FIFO structures, the order of deletion from a priority queue is determined by the element priority (优先度). Elements are deleted either in increasing or decreasing order of priority rather than in the order in which they arrived in the queue. A priority queue is efficiently implemented using the heap data structure, which is a complete binary tree that is most efficiently stored using the formula based representation.

9.1 引言 优先队列 优先队列(priority queue)是0个或多个元素的集合, 每个元素都有一个优先权或值。 9.1 引言 优先队列 优先队列(priority queue)是0个或多个元素的集合, 每个元素都有一个优先权或值。 对优先队列执行的操作有: 1)查找一个元素 2)插入一个新元素 3)删除一个元素

优先队列 两种优先队列: 最小优先队列(Min priority queue) 最大优先队列(Max priority queue) 优先权队列中的元素可以有相同的优先权。

最大优先权队列的抽象数据类型描述 抽象数据类型 MaxPriorityQueue{ 实例 有限的元素集合,每个元素都有一个优先权 操作 Create():创建一个空的优先队列 Size():返回队列中的元素数目 Max():返回具有最大优先权的元素 Insert(x):将x插入队列 DeleteMax(x):从队列中删除具有最大优先权的元素,并将该元素返回至x } 最小优先权队列的抽象数据类型描述?

优先队列的描述 优先队列的描述 线性表 堆(Heaps) 左高树(Leftist trees)

9.2 线性表 采用无序线性表描述最大优先队列 采用有序线性表描述最大优先队列 公式化描述(利用公式Location(i)=i-1) 9.2 线性表 采用无序线性表描述最大优先队列 公式化描述(利用公式Location(i)=i-1) 插入:表的右端末尾执行,时间: (1) ; 删除:查找优先权最大的元素,时间: (n) ; 使用链表, 插入:在链头执行,时间: (1) ; 删除: (n) ; 采用有序线性表描述最大优先队列 公式化描述(利用公式Location(i)=i-1,元素按递增次序排列) 插入: O(n) ;删除: O(1) ; 使用链表(按递减次序排列)

9.3 堆(Heaps) 9.3.1 定义 定义[最大树(最小树)] 每个节点的值都大于(小于)或等于其所有子树中节点(如果有的话)值。 A max tree (min tree) is a tree in which the value in each node is greater (less) than or equal to those in its children (if any) 最大树或最小树不一定必须是二叉树。

例:最小树 2 4 9 3 8 7

例:最大树 9 4 8 2 7 3 1

最大树 最小树

The definition of Max(Min) Heap A max heap (min heap) is a max (min) tree that is also a complete binary tree. 即若限定最大( 最小树)为2叉完全树,则称为堆。

定义[最大堆(最小堆)] :最大(最小)的完全二叉树。

最小堆 2 4 6 7 9 3 8

最大堆 9 8 6 7 2 5 1

堆是完全二叉树,可用一维数组有效地描述堆. 9 8 6 7 2 5 1 9 8 7 6 7 2 6 5 1 …… 0 1 2 3 4 5 6 7 8 9 10

9.3.2 最大堆的插入 思想:先插入到最后一个位置,然后沿通向根的路径调整 9 8 6 7 2 5 1 新元素是5

9.3.2 最大堆的插入 9 8 6 7 2 5 1 20 新元素是20

9.3.2 最大堆的插入 9 8 6 7 2 5 1 20

9.3.2 最大堆的插入 9 6 7 2 5 1 8 20

9.3.2 最大堆的插入 6 7 2 5 1 8 9 20

9.3.2 最大堆的插入 插入的时间复杂性: 每一层的工作,耗时:(1) 实现插入策略的时间复杂性为:O(height) = O(log2n), ( n 是堆的大小)

9.3.3 最大堆的删除 思想:取走根的元素,然后把最后元素放到根,按最大树的性质向下调整 20 6 7 2 5 1 15 8 9

9.3.3 最大堆的删除 6 7 2 5 1 15 8 9 最大元素被删除以后

9.3.3 最大堆的删除 6 7 2 5 1 15 8 9 具有10个节点的堆. 在堆中重新插入8 .

9.3.3 最大堆的删除 6 7 2 5 1 15 9 8 需要进行调整(或重构)。左子树和右子树是最大堆

9.3.3 最大堆的删除 6 7 2 5 1 9 15 8

9.3.3 最大堆的删除 6 7 2 5 1 8 15 9

9.3.3 最大堆的删除 删除的时间复杂性: 删除的时间复杂性与插入的时间复杂性相同. 每一层的工作,耗时:(1) 实现删除策略的时间复杂性为:O(height) = O(log2n), ( n 是堆的大小)

9.3.4 最大堆的初始化 We can construct the initial nonempty heap by performing n insertions into an initial empty heap. The total time taken by n insertion is O(nlog2n). We may initialize the heap in O(n) time by a different strategy. The main idea is that Let the array of n element be a complete binary tree, then convert it into a max-heap. Beginning at the element at i= n/2 ,adjust the subtree rooted i into a heap. Following the adjust, we examine the subtrees rooted at i-1,i-2,…,1

9.3.4 最大堆的初始化 a = [20,12,35,15,10,80,30,17,2,1] n=10, n/2=5 [1] [3] 9.3.4 最大堆的初始化 a = [20,12,35,15,10,80,30,17,2,1] n=10, n/2=5 [1] 20 [3] [2] 12 35 [5] [7] [4] [6] 15 10 80 30 i 17 2 1 [9] [8] [10]

9.3.4 最大堆的初始化 a = [20,12,35,15,10,80,30,17,2,1] n=10, n/2=5 [1] [3] 9.3.4 最大堆的初始化 a = [20,12,35,15,10,80,30,17,2,1] n=10, n/2=5 [1] 20 [3] [2] 12 35 [5] [7] [4] [6] 15 10 80 30 i 17 2 1 [10] [8] [9] 33

[1] 20 [3] [2] 12 35 [5] [4] [6] 17 10 80 30 15 2 1 [10] [8] [9]

[1] 20 [3] 12 [2] 80 [5] [4] [6] 17 10 35 30 i 15 2 1 [10] [8] [9]

[1] 20 [3] [2] 17 80 [5] [4] [6] 15 10 35 30 i 12 2 1 [10] [8] [9]

[1] 80 [3] [2] 17 20 [5] [4] [6] 15 10 35 30 i 12 2 1 [10] [8] [9]

[1] 80 [3] [2] 17 35 [5] [4] [6] 15 10 20 30 i 12 2 1 [10] [8] [9]

9.3.5 类MaxHeap template <classT> class MaxHeap{ public: MaxHeap(int MaxHeapSize = 10); ~MaxHeap( ) {delete [] heap;} int Size( ) const {return CurrentSize;} //返回元素数 T Max( ) //取最大值 {if (CurrentSize = = 0) throw OutOfBounds( ); return heap[1];} MaxHeap<T>& Insert(const T& x); MaxHeap<T>& DeleteMax(T& x); void Initialize(T a[], int size, int ArraySize); private: int CurrentSize, MaxSize; T *heap; // 指向一维数组的指针,heap是一维数组的名 } ;

堆是完全二叉树,可用一维数组有效地描述堆. 9 8 6 7 2 5 1 9 8 7 6 7 2 6 5 1 …… 0 1 2 3 4 5 6 7 8 9 10 currentsize Maxsize heap

MaxHeap构造函数 template<class T> MaxHeap<T>::MaxHeap(int MaxHeapSize) {// 构造函数 MaxSize = MaxHeapSize; heap = new T[MaxSize+1]; CurrentSize = 0; }

template<class T> MaxHeap<T>& MaxHeap<T>::Insert(const T& x) {// 把x 插入到最大堆中 if (CurrentSize = = MaxSize) throw NoMem(); // 没有足够空间 //为x寻找应插入位置 // i 从新的叶节点开始,并沿着树上升 int i = ++CurrentSize; //新的空位置 while (i != 1 && x > heap[i/2]) { //不能够把x放入heap[i] heap[i] = heap[i/2]; // 将元素下移 i /= 2; // 指针移向父节点 } heap[i] = x; return *this;

template<class T> MaxHeap<T>& MaxHeap<T>::DeleteMax(T& x) {// 将最大元素放入x ,并从堆中删除最大元素 if (CurrentSize = = 0) throw OutOfBounds(); // 检查堆是否为空 x = heap[1]; // 取走最大元素 // 重构堆 T y = heap[CurrentSize--]; // 先取最后元素,然后修改指针 // 从根开始,自上而下的为y 寻找合适的位置 int i = 1, // current node of heap ci = 2; // left child of i while (ci <= CurrentSize) { if (ci < CurrentSize && heap[ci] < heap[ci+1]) ci++; //ci是值大的孩子 if (y >= heap[ci]) break;//大于两个孩子了,退出寻找位置循环, heap[i] = heap[ci]; // 否则将ci代表的孩子上移 i = ci; //沿ci为根的子树继续寻找放入位置 ci *= 2; } heap[i] = y; return *this;

if (c < CurrentSize && heap[c] < heap[c+1]) c++) void MaxHeap<T>::Initialize(T a[], int size, int ArraySize) {// 把数组a初始化为最大堆. delete [] heap; heap = a; CurrentSize = size; MaxSize = ArraySize;//按用户需求定义堆的大小 // 产生一个最大堆 for (int i = CurrentSize/2; i >= 1; i--) {// 从n/2位置开始调整初始堆 T y = heap[i]; // i 为需要调节子树的根,暂时取出,留个工作位置 // 根值暂时放在y int c = 2*i; // c为i 的左儿子 while (c <= CurrentSize) { // heap[c] 应是较大的同胞节点 if (c < CurrentSize && heap[c] < heap[c+1]) c++) if (y >= heap[c]) break; // 不需要调节,退出循环 // 沿以ci为根的子树向下调节,利用while循环,只需改变根 heap[c/2] = heap[c]; // 将孩子上移.第一次放在 i的位置 c *= 2; // 下移一层 } heap[c/2] = y;

Initialize(T a[], int size, int ArraySize)把数组a初始化为最大堆。 为避免调用堆的析构函数时将数组a删除,在MaxHeap类中增加Deactive(使得无效)函数。 Void Deactive() {heap=0;}

初始化堆的时间复杂性: 堆的高度 = h. 在j层节点的数目 <= 2j-1. 以j层节点为根的子树的高度 = h-j+1 调整(或重构)以j层节点为根的子树时间(高度)O(h-j+1). 调整(或重构)所有以j层节点为根的子树: <= 2j-1(h-j+1) = t(j). 总的时间: t(1) + t(2) + … + t(h-1)=O( = =O(2h) =O(n).

Leftist tree(左高树) Despite the heap is both space and time efficient, it is not suitable for all applications of priority queues, i.e., combine or blend(混合) pairs of priority queues, as well as those in which we have multiple queues of varying size. Leftist tree structures are suitable for these applications

9.4 左高树(Leftist Trees) 左高树 高度优先左高树(HBLT— height-biased leftist tree ) 重量优先左高树(WBLT —weight-biased leftist tree) 最大/最小 WBLT

Consider a binary tree in which a special node called an external node replaces each empty tree. The remaining nodes are called internal node. A binary tree with external nodes added is called an extended binary tree.

扩充二叉树(Extended Binary Tree) 外部节点( External node) –代替树中的空子树的节点。 内部节点( Internal node) – 具有非空子树的节点。 扩充二叉树( Extended binary tree) –增加了外部节点的二叉树.

例:一个二叉树

扩充二叉树 外部节点的数目是: n+1

函数 s() Let S(x) be the length of a shortest path from node x to an external node in its subtree.

s()的计算 x是外部节点,则 s(x) = 0. 否则, s(x) = min {s(L), s(R)} + 1 其中L与R分别为x的左右孩子。 s() values may be computed easily using a postorder traversal. 54 54

s()的值 1 2

高度优先左高树 (HBLT) 定义[高度优先左高树] 当且仅当一棵二叉树的任何一个内部节点,其左孩子的s 值右孩子的s 值时,该二叉树为高度优先左高树(height-biased leftist tree, HBLT)。 对每一个内部节点 x, s(L) >= s(R),其中L与R分别为x的左右孩子。 图所示的二叉树是 HBLT?

一个左高树 1 2

高度优先左高树 (HBLT) 定理9-1:令x 为一个HBLT的内部节点,则 (a)以x 为根的子树的节点数目至少2s(x) – 1 (b)若以x 为根的子树有m 个节点,则s(x)最多为log2(m+1) (c)通过最右从x到达外部节点的路径(即,此路径是从x 开始沿右孩子移动)的路径长度为s(x) . 证明:s (x) 对应于以x节点为根的一个完全2叉子树子树的高度,而满2叉树的顶点数为2s(x) – 1 。而以x为根的子树还可能有其他节点,故根据满2叉树的性质,a)和b)成立。C)根据函数 s的定义:s(x) = min {s(L), s(R)} + 1,以及在HBLT中,s(L)s(R), 故c成立。即最短路一定在沿着右孩子的方向上。

最大/最小 HBLT Definition A max HBLT is an HBLT that is also a max tree. A min HBLT is an HBLT that is also a min tree.

最大/最小 HBLT 定义[最小HBLT] 即同时又是最小树的HBLT 。

重量优先左高树 (WBLT) 定义x的重量w(x), 为以x 为根的子树的内部节点数目。 定义[重量优先左高树]( WBLT—weight-biased leftist tree, ):当且仅当一棵二叉树的任何一个内部节点,其左孩子的w 值大于等于右孩子的w 值时。 [最大(小)WBLT] 该二叉树为重量优先左高树即同时又是最大(小)树的WBLT。

重量优先左高树 (WBLT) Not a WBLT

Operations on HBLTs Since the way in which finds, insert, delete, meld and initializations are done in WBLTs and HBLTs is similar, consequently we describe these operations for HBLTs only.

Insert and delete for HBLT insertion element x into a Max HBLT H 1) create a max HBLT T with x only 2) meld (合并) two Max HBLT H and T into a new Max HBLT Deletion from a Max HBLT H 1) delete the root of H; 2) meld two max HBLT leftsubtree and rightsubtree into a new Max HBLT

Melding two max HBLTs recursively Let A and B be the two max HBLTs being melded. If (A or B =empty) then return the nonempty one else { root = max{root(A),root(B)}; let A be the tree with the max roots, L is its left subtree, then meld the right subtree of A and B into C; If the s value of L is smaller than that of C then let C be the left subtree; A as its root and L be the right subtree; otherwise exchange C and L in the above processing.

A A C B AL AR C? AL?

1 S=1 9 1 7 1 9 7 1 a b c 1 2 1 10 10 7 1 1 7 1 5 5 e d

1 2 18 10 1 6 1 1 7 5 f 18 6 10 7 5

MAX HBLT的插入 对给定元素x,插入到MAX HBLT H 中 1) 建立一棵仅含有x的树 B; 2)meld (H,B)

9.4.2 最大HBLT的插入 Insert(7) 6 4 2 8 3 5 9

9.4.2 最大HBLT的插入 Insert(7) 6 4 2 8 3 5 9 7 创建一棵单元素最大HBLT.

9.4.2 最大HBLT的插入 Insert(7) 6 4 2 8 3 5 9 7

最大HBLT删除 最大HBLT H, 删除元素应该是H 的根(具有最大值),meld (Lefttree(H),Righttree(H))

9.4.3 最大HBLT的删除 6 4 2 8 3 5 9

9.4.3 最大HBLT的删除 9 具有最大的根 6 4 8 2 3 5 删除根节点. 合并两棵子最大HBLT。

9.4.3 最大HBLT的删除 具有最大的根 6 4 8 5 3 2

9.4.4 合并两颗最大HBLT

9.4.5 初始化最大HBLT 方法1. 通过将n 个元素插入到最初为空的最大HBLT中来对其进行初始化. 时间为:O(nlogn)

9.4.5 初始化最大HBLT 时间复杂性: O(n) 方法2. 1、创建n 个最大HBLT ,每个树中仅包含n 个元素中的某一个,这n 棵树排成一个FIFO队列, 2、从队列中依次删除两个最大HBLT ,将其合并,然后再加入队列末尾。 重复第2步,直到最后只有一棵最大HBLT 。 时间复杂性: O(n)

9.4.5 初始化最大HBLT 元素:7,1, 9, 11,2 7 1 9 11 2 7 1 9 11 2

9.4.5 初始化最大HBLT 7 1 9 11 2 7 1 9 11 2 7 1 9 11 2 81

9.4.5 初始化最大HBLT 时间复杂性 为简单起见,假设n 是2的幂次方。 合并n / 2对具有1个元素的最大HBLT,每次合并O(1)。 合并n/ 4对含有2个元素的最大HBLT ,每次合并O(2)。 合并n/ 8对含有4个元素的最大HBLT ,每次合并O(3)。 ⋯ ⋯ 。 合并两棵含2i 个元素的最大HBLT,每次合并O(i+1), 合并1对含n/2 (2k-1)个元素的最大HBLT,每次合并O(k) 因此总时间为: O(n/2+2*(n/4)+3*(n/8)+…+k*(n/2h)) = O(ni/2i)=O(n)

9.4.6 类MaxHBLT 程序9-6 HBLT的节点类 程序9-7 MaxHBLT类 程序9-8 合并两棵左高树

程序9-6 HBLT的节点类 class HBLTNode { friend MaxHBLT < T > ; public: HBLTNode(const T& e, const int sh)//构造函数只需2个参数 {data = e; s = sh; LeftChild = RightChild = 0;} private: int s; // 节点的s 值 T data; HBLTNode<T> *LeftChild, *RightChild; } ;

程序9-7 MaxHBLT类 template<class T> class MaxHBLT { public: MaxHBLT() {root = 0;} ~MaxHBLT() {Free(root);} T Max() {if (!root) throw OutOfBounds(); return root->data;} MaxHBLT<T>& Insert(const T& x); MaxHBLT<T>& DeleteMax(T& x); MaxHBLT<T>& Meld(MaxHBLT<T>& x) { Meld(root, x.root); x.root = 0; //禁止对x为根的子树访问 return *this;} void Initialize(T a[], int n); private: void Free(HBLTNode<T> *t); void Meld(HBLTNode<T>* &x, HBLTNode<T>* y); HBLTNode<T> *root; // 指向树根的指针 } ; 程序9-7 MaxHBLT类 x和本树合并

程序9-8 合并两棵左高树 template<class T> void MaxHBLT<T>::Meld(HBLTNode<T>* &x, HBLTNode<T>* y) {// 合并两棵根分别为* x和* y的左高树, 返回指向新根x的指针 if (!y) return; // y 为空 if (!x) // x为空 {x = y; return;} // x和y 均为空 if (x->data < y->data) Swap(x,y); // 现在x->data >= y->data Meld(x->RightChild, y ) ; //递归先把x的右子树与y归并,并作为x的右子树

程序9-8 合并两棵左高树(续) if (!x->LeftChild) {// 左子树为空 // 交换子树 x->LeftChild = x->RightChild; x->RightChild = 0; x->s = 1;} //无右孩子 else {// 检查是否需要交换子树 if (x->LeftChild->s < x->RightChild->s) Swap(x->LeftChild,x->RightChild); x->s = x->RightChild->s + 1;}//修改x自身的s值 }

Insert template<class T> MaxHBLT<T>& MaxHBLT<T>::Insert(const T &x) {// Insert x into the leftist tree // Creat a tree with one node HBLTNode<T> *q= new HBLTNode<T> (x,1) //根据其构造函数x =data, s=1, 左右儿子为空 // meld q and original tree Meld (root,q); Return *this; }

Delete template<class T> MaxHBLT<T>& MaxHBLT<T>::DeleteMax(T &x) {// Delete the Max element and put it in x if (!root) throw OutOfBounds(); x=root->data; HBLTNode<T> *L = root->LeftChild; HBLTNode<T> *R = root->RightChild; Delete root; root = L; Meld (root,R) Return *this; }

Initialization Q.Add(q); }//n 个一个顶点的左高树加入到Q template<class T> Void MaxHBLT<T>::Initialize(T a[], int n) {Queue<HBLTNode<T> *> Q(n);//difne a Queue with size=n Free(root); for (int i=1; i<=n; i++) { HBLTNode<T> *q = new HBLTNode<T> (a[i],1); Q.Add(q); }//n 个一个顶点的左高树加入到Q //repeat meld from Q HBLTNode<T> *b, *c; for (int i=1, i<=n-1; i++) { Q.Delete(b).Delete(c ); //从Q中连续取出2个左高树 Meld(b,c) ; Q.Add(b); }; //当循环结束时,Q中只完成合并的树,n>1 If (n) Q.Delete(root); // n>1时,把最终合并的树指针赋值给root }

9.5 应用 9.5.1 堆排序 9.5.2 机器调度 9.5.3 霍夫曼编码

9.5.1 堆排序(Heap Sort) 可利用堆来实现n个元素的排序,每个元素的关键值为优先权。 堆排序算法: 每次从堆中提取(即删除)元素。 如果使用最大堆,各元素将按非递增次序排列。 如果使用最小堆,各元素将按非递减次序排列。

例:堆排序 A=[20,12,35,15,10,80,30,17,2,1] 2 80 30 17 35 1 20 10 12 15

例:堆排序 初始化最大堆 2 20 30 12 35 1 80 10 17 15

例:堆排序 80 35 30 20

堆排序实现 template <class T> void HeapSort(T a[], int n) {// 利用堆排序算法对a[1:n] 进行排序 MaxHeap<T> H(1); H.Initialize(a,n,n); // 创建一个最大堆 // 从最大堆中逐个抽取元素 T x; for (int i = n-1; i >= 1; i--) { H.DeleteMax(x); a[i+1] = x; } H.Deactivate(); // 在堆的析构函数中保存数组a

堆排序的时间复杂性分析 对n 个元素进行排序: 初始化所需要的时间为:(n) 每次删除所需要的时间为: O(logn) 因此总时间为: O(nlogn)//n次循环

9.5.3 霍夫曼编码(Huffman Codes) 基于LZW算法的文本压缩工具,利用了字符串在文本中重复出现的规律。

字符编码 假设: 每个字符用一个byte(8bit)来存贮. 每个字符用2bit编码来存贮. 文本是由a,x, u, z组成的字符串; 这个字符串的长度为:1000 每个字符用一个byte(8bit)来存贮. 字符串: 1000 字符,1000byte(8000bit). 每个字符用2bit编码来存贮. 字符串: 1000 字符,2000byte. a:00; x:01; u: 10; z:11 字符串: 2000位,可以减少 6000bit

霍夫曼编码 不采用均匀对每个符号分配bit数,而是给出现频率高的字符短编码,出现频率低的长编码。 E.g. 采用均匀编码,每个字符的编码长度= log2 (符号个数) aaxuaxz  log(4)=2, a=00,x=01,u=10,z=11 00000110000111 (编码总长度:14bits) a(frequency 3), x(2), u(1), z(1) a=0, x=10, u=110, z=111 0010110010111 (13 bit), 若(996,2,1,1), 则按频率为1006bit,2位编码2000 bit

霍夫曼编码 霍夫曼编码根据不同符号在一段文字中的相对出现频率来设计压缩编码。 频率(frequency):一个字符出现的次数称为频率 . aaxuaxz: 频率: a:3 x:2 u:1 z:1

霍夫曼树(Huffman Trees) 扩充二叉树的加权外部路径长度(Weighted External Path length ) : L(i) —从根到达外部节点i 的路径长度(即路径的边数); F(i) —外部节点i 的权值(weight) . 如果F(i)是字符串中被编码的字符的频率, WEP 就是压缩编码串的长度. 霍夫曼树:对于给定的频率具有最小加权外部路径长度 的二叉树。 102

构造霍夫曼树 构造霍夫曼树: 1. 初始化二叉树集合,每个二叉树含一个外部节点,每个外部节点代表字符串中一个不同的字符,外部节点的权重为频率. 2. 从集合中选择两棵具有最小权重的二叉树,并把它们合并成一棵新的二叉树。合并方法是把这两棵二叉树分别作为左右子树,然后增加一个新的根节点。新二叉树的权重为两棵子树的权重之和。 3.重复第2步,直到仅剩下一棵树为止。 4. 从根向下,对每个顶点,若有孩子,则分配左儿子边为0,右面为1。 5.每个字符的编码为从根到对应外部节点路径上的字符串。 103

构造霍夫曼树示例 104

a: 00 b: 010 c: 011 d: 100 e: 101 f: 11 a b c d e f 27 1 105

利用霍夫曼编码进行文本压缩编码 利用霍夫曼编码对字符串或一段文本进行压缩编码: 1.确定不同字符的频率。 2. 建立具有最小加权外部路径的二叉树(即霍夫曼树),树的外部节点用字符串中的字符表示,外部节点的权重(weight)即为该字符的频率。 3.遍历从根到外部节点的路径得到每个字符的编码。 4.用字符的编码来代替字符串中的字符。

构造霍夫曼树的实现 使用一个最小堆来存储二叉树集合。 最小堆的每个元素包括两部分: template<class T> 二叉树的权值. template<class T> class Huffman { friend BinaryTree<int> HuffmanTree(T[],int); public: operator T() const {return weight;} private: BinaryTree<int> tree; T weight; };

template <class T> BinaryTree <int> HuffmanTree(T a[],int n) {// 根据权重a [1 : n]构造霍夫曼树 // 创建一个单节点树的数组 Huffman<T> *w = new Huffman<T> [n+1]; BinaryTree<int> z, zero; for (int i = 1; i <= n; i++) { z.MakeTree(i,zero,zero);//i = 树的编号 w[i].weight = a[i];//频率数 w[i].tree = z; } // 把数组变成一个最小堆 MinHeap <Huffman<T> > H(1); H.Initialize(w,n,n);

//将堆中的树不断合并 Huffman <T> x,y; for(i=1;i<n;i++){ H.DeleteMin(x); H.DeleteMin(y); z.MakeTree(0,x.tree,y.tree);//形成新树z, 0没特殊意义 x.weight+=y.weight; x.tree=z; H.Insert(x); //把合并树加入到堆中,树的数目-1 } H.DeleteMin(x);//最后的树 H.Deactivate( ); delete[]w; Return x.tree;

作业:8,9,14,16,23

练习题 1. 一组序列的关键码为: {28、19、27、49、56、12、10、25} 2.在一段文字中,7个常用汉字及出现频度如下: 该序列是否是堆?若不是,写出建立的初始堆(最大堆)。 利用堆排序的方法对该序列进行非递减排列,给出堆排序的主要过程。 给出在初始堆中插入一新元素60后的堆结构。 2.在一段文字中,7个常用汉字及出现频度如下: 的 地 于 个 和 是 有 20 19 18 17 15 10 1 要求: ⑴ 画出对应的Huffman树; ⑵ 求出每个汉字的Huffman编码。

练习题 1. 一组序列的关键码为: {28、19、27、49、56、12、10、25} 2.在一段文字中,7个常用汉字及出现频度如下: 该序列是否是堆?若不是,写出建立的初始堆(最大堆)。 利用堆排序的方法对该序列进行非递减排列,给出堆排序的主要过程。 给出在初始堆中插入一新元素60后的堆结构。 2.在一段文字中,7个常用汉字及出现频度如下: 的 地 于 个 和 是 有 20 19 18 17 15 10 1 要求: ⑴ 画出对应的Huffman树; ⑵ 求出每个汉字的Huffman编码。