堆 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 }

 

运行效果:

 

posted @ 2022-06-16 14:47  天外仙宗  阅读(95)  评论(0)    收藏  举报