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 }

 

posted @ 2020-04-03 21:29  PennyXia  阅读(154)  评论(0编辑  收藏  举报