堆(Heap)是计算机科学中一类特殊的数据结构,是最高效 的优先级队列。堆通常是一个可以被看做一棵完全二叉树的数组对象。
逻辑结构是便于人理解而形成的一种结构。
上文提到,堆可以被看成一棵完全二叉树,那么堆的逻辑结构就可以用二叉树来表示。
物理结构是计算机存储数据时应用的一种结构。
堆的重要功能是存储数据,所以堆实际上是用一维数组存储数据,堆的物理结构就是一维数组。
所有的父节点都大于等于子节点。
所有的父节点都小于等于子节点。
这种操作主要用于在堆尾部插入一个数据。
这里我以把现有的堆调成大堆为例。
操作流程:破坏了堆序性的节点和他的父节点比较,如果他比父节点大,则交换他们,循环这样的操作,直到该节点来到堆的顶或者满足大堆才停止循环。
void AdjustUp(HPDataType* a, int child)
9 {
10 int parent = (child - 1) / 2;
11 while (child > 0)
12 {
13
14 if (a[child] < a[parent])
15 {
16 //交换
17 Swap(&a[child], &a[parent]);
18 //迭代,更新child和parent
19 child = parent;
20 parent = (parent - 1) / 2;
21 }
22 else
23 {
24 break;
25 }
26
27 }
28 }
29
这种操作主要用于在堆顶部插入一个数据。
这里我以把现有的堆调成大堆为例。
操作流程:根节点和他的孩子节点中较大的比较(这里我后文直接说成和大孩子比较噢),如果根节点比大孩子小,则交换他们,循环这样的操作,直到根节点来到堆的底或者满足大堆才停止循环。
//size是数组的元素个数,root是根节点
31 void AdjustDown(HPDataType* a, int size, int root)
32 {
33 size_t parent = root;
34 size_t child = parent * 2 + 1;
35 while (child < size)
36 {
37 // 1、选出左右孩子中大的那个
38 if (child + 1 < size && a[child + 1] >a[child])
39 {
40 ++child;
41 }
42
43 // 2、如果孩子大于父亲,则交换,并继续往下调整
44 if (a[child] > a[parent])
45 {
46 Swap(&a[child], &a[parent]);
47 parent = child;
48 child = parent * 2 + 1;
49 }
50 else
51 {
52 break;
53 }
54 }
55
56 }
57
操作流程:插入一个数–>向上调整
操作流程:先建好一个堆,在底部插入一个数–>从该节点的父节点向下调整。
假设要在堆底插入一个数
插入一个新节点–>数组size+1–>向上调整(保持原来的堆序性)
//插入一个数
97 //在堆底插入一个数
98 void HPPush(HP* php, HPDataType x)
99 {
100 assert(php);
101 if (php->capacity == php->size)
102 {
103 int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
104 HPDataType* tmp = realloc(php->a,sizeof(HPDataType) * newcapacity);
105 if (tmp == NULL)
106 {
107 printf("error");
108 exit(-1);
109 }
110 php->a = tmp;
111 php->capacity = newcapacity;
112
113 }
114 php->a[php->size ] = x;
115 php->size++;
116 //向上调整
117 AdjustUp(php->a, php->size-1);
118
119 }
假设要删除堆底的一个数
交换堆底节点和根节点–>数组size-1–>向下调整(保持原来的堆序性)
//删除一个数
121 void HPPop(HP* php)
122 {
123 assert(php);
124 assert(php->size > 0);
125 Swap(&php->a[0],& php->a[php->size - 1]);
126 php->size--;
127 AdjustDown(php->a, php->size, 0);
128 }
129
//初始化函数
66 void HPInit(HP* php)
67 {
68 assert(php);
69 php->a = NULL;
70 php->capacity = php->size = 0;
71 }
//打印函数
73 void HPPrint(HP* php)
74 {
75 int i = 0;
76 for (i = 0; i < php->size; i++)
77 {
78 printf("%d ", php->a[i]);
79 }
80 printf("\n");
81 }
这里注意:
⚠️要改变传过来的两个数,要传指针。
//交换函数
59 void Swap(HPDataType* pa, HPDataType* pb)
60 {
61 HPDataType tmp = *pa;
62 *pa = *pb;
63 *pb = tmp;
64 }
//得到堆顶元素
139 HPDataType HPTop(HP* php)
140 {
141 assert(php);
142 assert(php->size > 0);
143 return php->a[0];
144
145 }
bool类型返回【0】或【1】
⚠️这里返回的是表达式,中间用==链接。
bool HPEmpty(HP* php)
84 {
85 return php->size == 0;
86 }
//得到堆元素个数
132 size_t HPSize(HP* php)
133 {
134 assert(php);
135 return php->size;
136 }
137
//销毁空间
88 void HPDestroy(HP* php)
89 {
90 assert(php);
91 free(php->a);
92 php->a = NULL;
93 php->capacity = php->size = 0;
94 }
95