堆
2.5堆(Heap)的定义和性质
2.5.1堆的定义
优先队列:特殊的“队列”,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序。
堆的两个特性:
- 结构性:用数组表示的完全二叉树
- 有序性:任一结点的关键字是其子树所有节点的最大值或最小值,最大堆(Max Heap),也称为大顶堆最小堆(Min Heap),也称为小顶堆
2.5.2最大堆的创建(初始化空堆)
1 //用数组存储一个堆 2 typedef struct Heap* MaxHeap; 3 struct Heap { 4 int* Elements;//指向存储堆元素的数组 5 int Size;//堆的当前元素个数 6 int Capacity;//堆的最大容量 7 }; 8 9 MaxHeap Create(int MaxSize) { 10 MaxHeap H = (MaxHeap)malloc(sizeof(Heap)); 11 //从下标为1的位置开始存放 12 H->Elements = (int*)malloc((MaxSize + 1) * sizeof(int)); 13 H->Size = 0; 14 H->Capacity = MaxSize; 15 H->Elements[0] = MaxData;//"哨兵",大于堆中所有元素的值 16 return H; 17 }
2.5.3最大堆的插入
将新增结点插入到从其父结点到根结点的有序序列中。
注意,因为有哨兵的存在,所以当i=1的时候循环必然会停止执行
1 //最大堆的插入 插入元素item 2 void InsertMaxHeap(MaxHeap H, int item) { 3 int i; 4 if (H->Size == MaxSize) { 5 cout << "最大堆已满"; 6 return; 7 } 8 else { 9 i = ++H->Size;//i指向插入后堆中最后一个元素的位置 10 for (; H->Elements[i / 2] < item; i /= 2) {//如果父结点更小 11 H->Elements[i] = H->Elements[i / 2];//将父结点的值赋给当前结点 12 } 13 H->Elements[i] = item; 14 } 15 }
2.5.4最大堆的删除
取出根结点(最大值)元素,同时删除堆的一个结点(最后一个结点),等效于将最后一个结点的元素值替换最大的元素,然后调整成最大堆。
1 //最大堆的删除 2 int DeleteMaxHeap(MaxHeap H) { 3 int parent, child; 4 int MaxItem, tmp; 5 if (Isempty(H)) { 6 cout << "最大堆已空"; 7 return 0; 8 } 9 MaxItem = H->Elements[1];//第一个元素最大 10 tmp = H->Elements[H->Size--];//记录最后一个元素 11 for (parent = 1; parent * 2 <= H->Size; parent = child) { 12 child = parent * 2;//左儿子 13 //parent表示tmp当前的位置 14 if (child != H->Size&&H->Elements[child] < H->Elements[child + 1]) 15 child++; 16 if (tmp >= H->Elements[child])break; 17 else 18 H->Elements[parent] = H->Elements[child]; 19 } 20 H->Elements[parent] = tmp;//返回的parent是tmp最终的位置 21 return MaxItem; 22 }
2.5.5最大堆的建立
建立最大堆:将已经存在的N个元素按最大堆的要求存放在一个一维数组中
【注】:对于一组相同数据,插入建堆和调整建堆建出来的堆也许不一样
【例题】:
【分析】:
1
2 3
4 5 6 7
8 9 10 11 12
建堆的话,主要考虑下沉的次数,以此定义高度。
这样的话,8,9,10,11,12都是已经沉底的,要注意的是7也是在最底了。这些节点高度都是0。
4,5,6都是最多可以沉1次的,高度为1.
2,3最多能沉2次,高度为2.
1可以沉3次,高度为3.
1*3+2*2+3*1=3+4+3=10
2.5.5.1方法一:插入建堆
1 //插入建堆 2 #include "pch.h" 3 #include <iostream> 4 #include <cstdlib> 5 using namespace std; 6 #define MaxSize 100 7 #define MaxData 100 8 9 //用数组存储一个堆 10 typedef struct Heap* MaxHeap; 11 struct Heap { 12 int* Elements;//指向存储堆元素的数组 13 int Size;//堆的当前元素个数 14 int Capacity;//堆的最大容量 15 }; 16 17 MaxHeap Create() { 18 MaxHeap H = (MaxHeap)malloc(sizeof(Heap)); 19 //从下标为1的位置开始存放 20 H->Elements = (int*)malloc((MaxSize + 1) * sizeof(int)); 21 H->Size = 0; 22 H->Capacity = MaxSize; 23 H->Elements[0] = MaxData;//"哨兵",大于堆中所有元素的值 24 return H; 25 } 26 27 //最大堆的插入 插入元素item 28 void InsertMaxHeap(MaxHeap H, int item) { 29 int i; 30 if (H->Size == MaxSize) { 31 cout << "最大堆已满"; 32 return; 33 } 34 else { 35 i = ++H->Size;//i指向插入后堆中最后一个元素的位置 36 for (; H->Elements[i / 2] < item; i /= 2) {//如果父结点更小 37 H->Elements[i] = H->Elements[i / 2];//将父结点的值赋给当前结点 38 } 39 H->Elements[i] = item; 40 } 41 } 42 43 //遍历输出 44 void HeapTraversal(MaxHeap H) { 45 for (int i = 1; i <= H->Size; i++) 46 cout << H->Elements[i] << " "; 47 } 48 49 int main() { 50 MaxHeap H; 51 H = Create(); 52 int n; 53 cin >> n; 54 for (int i = 0; i < n; i++) { 55 int t; 56 cin >> t; 57 InsertMaxHeap(H,t); 58 } 59 HeapTraversal(H); 60 return 0; 61 }
2.5.5.2方法二:调整建堆
从最后一个有孩子结点的结点开始,其本身结点和孩子结点共同构成"子最大堆",借助前面删除的想法,对每个"子最大堆"排序,最后一层层的整合,最后最大堆建成。
1 #include <iostream> 2 #include <cstdlib> 3 using namespace std; 4 #define MaxSize 100 5 #define MaxData 100 6 7 //用数组存储一个堆 8 typedef struct Heap* MaxHeap; 9 struct Heap { 10 int* Elements;//指向存储堆元素的数组 11 int Size;//堆的当前元素个数 12 int Capacity;//堆的最大容量 13 }; 14 15 MaxHeap Create() { 16 MaxHeap H = (MaxHeap)malloc(sizeof(Heap)); 17 //从下标为1的位置开始存放 18 H->Elements = (int*)malloc((MaxSize + 1) * sizeof(int)); 19 H->Size = 0; 20 H->Capacity = MaxSize; 21 H->Elements[0] = MaxData;//"哨兵",大于堆中所有元素的值 22 return H; 23 } 24 //将以i为根结点的子堆进行排序 25 void SortHeap(MaxHeap H,int i) { 26 int parent, child; 27 int tmp = H->Elements[i];//保存将要进行调整的结点 28 for (parent = i;parent*2<=H->Size; parent = child) { 29 child = parent * 2; 30 if (child != H->Size&&H->Elements[child] < H->Elements[child + 1]) 31 child++;//找到左右儿子中更大的一个 32 if (tmp > H->Elements[child])break; 33 else 34 H->Elements[parent] = H->Elements[child]; 35 } 36 H->Elements[parent] = tmp; 37 } 38 39 //调整 40 void adjust(MaxHeap H) { 41 for (int i = H->Size / 2; i > 0; i--) 42 SortHeap(H, i); 43 } 44 45 46 void HeapTraversal(MaxHeap H) { 47 for (int i = 1; i <= H->Size; i++) 48 cout << H->Elements[i] << " "; 49 } 50 51 int main() { 52 MaxHeap H; 53 H = Create(); 54 int n; 55 cin >> n; 56 for (int i = 0; i < n; i++) { 57 cin >> H->Elements[i+1]; 58 H->Size++; 59 } 60 adjust(H); 61 HeapTraversal(H); 62 return 0; 63 }
作者:PennyXia
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。