堆 C语言实现
在中文网络里搜索代码例程, 总有一种在垃圾堆里刨食的感觉,为了让垃圾堆里多一些有用的东西,我特意写了这个文章。本文章的代码是从别的地方抄来的,如果原作者不希望代码放在这里,请联系帖主删除帖子。
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <stdbool.h> 4 #include <assert.h> 5 #include <string.h> 6 7 typedef int HPDateType; 8 9 typedef struct Heap 10 { 11 HPDateType *a; 12 int size; 13 int capacity; 14 } HP; 15 16 void HeapInit(HP *php, HPDateType *a, int n); // 初始化一个堆 17 void HeapDestroy(HP *php); // 销毁一个堆,释放他的空间 18 void HeapPush(HP *php, HPDateType x); // 在堆里面插入一个数,并且让它的结构还是一个堆 19 void HeapPop(HP *php); // 删除堆的顶的数据,并且让它的结构还是一个堆 20 HPDateType HeapTop(HP *php); // 返回堆顶的数据 21 int HeapSize(HP *php); // 返回堆里面数据的个数 22 bool HeapEmpty(HP *php); // 判断堆是否为空 23 void HeapPrint(HP *php); // 输出一个堆 24 void AdjustUp(HP *st, int child); // 向上调整算法 25 void AdjustDown(HP *st, int praent); // 向下调整算法 26 void Swap(int *p1, int *p2); // 交换值 27 void HeapSort(HP *php); // 堆排序 28 29 30 31 /******************************************************************************************************************* 32 堆(heap) 33 什么是堆 34 定义 35 堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象 36 堆的物理结构是一个数组。也可以看成顺序表。元素是每一个结点的值。 37 之所以规定完全二叉树, 就是因为最下层的节点都尽量连续靠左,就可以用数组来表示了 38 性质 39 结构性:用数组表示的完全二叉树 40 有序性:任意节点的关键字(权值)是其子树所有节点的最大值(或最小值) 41 父节点大于子节点:最大堆(MaxHeap) 42 父节点小于子节点:最小堆(MinHeap) 43 应用 44 1. 优先队列 45 “优先队列” (Priority Queue)是特殊的“队列”,从队列中取出元素的顺序是依照元素的优先权(关键字)大小, 46 而不是元素进入队列的先后顺序 47 2. 堆排序, 用堆来实现的排序算法 48 堆的调整算法 49 1 向下调整算法 50 现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法 51 可以把它调整成一个小堆或大堆。但是向下调整算法有一个前提:左右子树必须是一个堆, 52 才能调整。所以我们必须从数组的最后一个非叶子节点开始往回对每一个非叶子节点,直到 53 根节点使用向下调整算法来调整维护这个堆。 54 2 向上调整算法 55 我们通过从最后一个叶子节点开始的向上调整算法可以把它调整成一个小堆或大堆。也是通过 56 根据此叶子节点找到父亲节点并开始调整,从最后一个叶子节点开始往回直到根节点位置是 57 使用向上调整算法来调整维护。 58 重要性质 59 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号, 60 则对于序号为i的结点有: 61 1.若i > 0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点 62 2.若2i + 1 < n,则左孩子序号:2i + 1, 2i + 1 >= n则无左孩子 63 3.若2i + 2 < n,则右孩子序号:2i + 2, 2i + 2 >= n则无右孩子 64 当得知子节点,反推父节点: f = (左n - 1) / 2 , f = (右n - 2) / 2 65 ***********************************************************************************************************************/ 66 67 68 69 70 int main(int argc, char **argv) 71 { 72 HP st; 73 int a[] = {15, 18, 28, 34, 65, 19, 49, 25, 37, 27}; 74 int n = sizeof(a) / sizeof(a[0]); 75 76 printf("\ntest HeapInit(), HeapPrint():\n"); 77 HeapInit(&st, a, n); 78 HeapPrint(&st); 79 80 printf("\ntest HeapPush(&st, 8):\n"); 81 HeapPush(&st, 8); 82 HeapPrint(&st); 83 84 printf("\ntest HeapPush(&st, 88):\n"); 85 HeapPush(&st, 88); 86 HeapPrint(&st); 87 88 printf("\ntest HeapPop(&st):\n"); 89 HeapPop(&st); 90 HeapPrint(&st); 91 92 printf("\ntest HeapPop(&st):\n"); 93 HeapPop(&st); 94 HeapPrint(&st); 95 96 printf("\n对堆进行排序:\n"); 97 HeapSort(&st); 98 HeapPrint(&st); 99 100 101 /* 销毁堆 */ 102 HeapDestroy(&st); 103 104 if(st.a == NULL) 105 printf("\n销毁堆成功\n"); 106 107 return 0; 108 } 109 110 // 交换 111 void Swap(int *p1, int *p2) 112 { 113 int temp = *p1; 114 *p1 = *p2; 115 *p2 = temp; 116 } 117 118 // 向上调整算法 119 void AdjustUp(HP *st, int child) 120 { 121 int parent = (child - 1) / 2; 122 123 while (child > 0) 124 { 125 if (st->a[child] < st->a[parent]) 126 { 127 Swap(&st->a[child], &st->a[parent]); 128 child = parent; 129 parent = (child - 1) / 2; 130 } 131 else 132 { 133 break; 134 } 135 } 136 } 137 138 // 向下调整算法 139 void AdjustDown(HP *st, int praent) 140 { 141 int child = praent * 2 + 1; 142 143 while (child < st->size) 144 { 145 if (child + 1 < st->size && st->a[child + 1] < st->a[child]) 146 { 147 child++; 148 } 149 150 if (st->a[child] < st->a[praent]) 151 { 152 Swap(&st->a[child], &st->a[praent]); 153 praent = child; 154 child = praent * 2 + 1; 155 } 156 else 157 { 158 break; 159 } 160 } 161 } 162 163 void HeapInit(HP *php, HPDateType *a, int n) 164 { 165 if (php == NULL) 166 return; 167 168 php->a = (HPDateType *)calloc(1, sizeof(HPDateType) * n); 169 170 if (php->a == NULL) 171 exit(EXIT_FAILURE); 172 173 memcpy(php->a, a, sizeof(HPDateType) * n); 174 php->capacity = n; 175 php->size = n; 176 177 int i; 178 179 //建小堆 180 for (i = (php->size - 2) / 2; i >= 0; i--) 181 AdjustDown(php, i); 182 } 183 184 void HeapDestroy(HP *php) 185 { 186 if (php == NULL) 187 return; 188 189 free(php->a); 190 php->a = NULL; 191 php->size = 0; 192 php->capacity = 0; 193 } 194 195 //在堆里面插入一个数,并且让它的结构还是一个堆 196 void HeapPush(HP *php, HPDateType x) 197 { 198 if (php == NULL) 199 return; 200 201 /* 如果堆的空间满了,就用realloc()重新扩大堆的数组空间的大小 */ 202 if (php->size == php->capacity) 203 { 204 HPDateType *temp = (HPDateType *)realloc(php->a, sizeof(HPDateType) * php->capacity * 2); 205 if (temp == NULL) 206 exit(EXIT_FAILURE); 207 208 php->a = temp; 209 php->capacity = php->capacity * 2; 210 } 211 212 php->a[php->size] = x; 213 php->size++; 214 215 AdjustUp(php, php->size - 1); 216 } 217 218 //删除堆的顶的数据,并且让它的结构还是一个堆 219 void HeapPop(HP *php) 220 { 221 if (php == NULL) 222 return; 223 224 if (HeapEmpty(php)) 225 return; 226 227 int end = php->size - 1; 228 229 Swap(&php->a[0], &php->a[end]); 230 php->size--; 231 232 AdjustDown(php, 0); 233 } 234 235 //返回堆顶的数据 236 HPDateType HeapTop(HP *php) 237 { 238 if (php == NULL) 239 return; 240 241 if (HeapEmpty(php)) 242 return; 243 244 return php->a[0]; 245 } 246 247 //返回堆里面数据的个数 248 int HeapSize(HP *php) 249 { 250 if (php == NULL) 251 return; 252 253 return php->size; 254 } 255 256 //判断堆是否为空 257 bool HeapEmpty(HP *php) 258 { 259 if (php == NULL) 260 return; 261 return (php->size == 0); 262 } 263 264 //将堆打印出来 265 void HeapPrint(HP *php) 266 { 267 int i; 268 int m = 1, n = 0; 269 270 printf("\n从上到下输出堆的内容:\n"); 271 272 for (i = 0; i < php->size; i++) 273 { 274 printf("%d ", php->a[i]); 275 if (i == n) 276 { 277 putchar('\n'); 278 m = m * 2; 279 n += m; 280 } 281 } 282 283 printf("\n\n"); 284 } 285 286 void HeapSort(HP *php) 287 { 288 int t = php->size; 289 290 while (php->size != 0) 291 { 292 HeapPop(php); 293 } 294 295 php->size = t; 296 }
运行效果:

浙公网安备 33010602011771号