【425】堆排序方法(二叉堆)优先队列(PQ)
参考:漫画:什么是二叉堆?
- 大根堆
- 小根堆
参考:漫画:什么是堆排序?
参考:漫画:什么是优先队列?
参考:【video】视频--第14周10--第8章排序10--8.4选择排序3--堆排序2--堆调整
堆的调整(小根堆)
- 输出堆顶元素之后,以堆中最后一个元素替代之;
- 然后将根节点值与左、右子树的根节点值进行比较,并与其中小者进行交换;
- 重复上述操作,直至叶子节点,将得到新的堆,称这个从堆顶至叶子的调整过程为“筛选”。
大根堆与上面类似。
通过3中方法实现ADT:
- 堆的形式
- 无序array
- 有序array
第一步:一组数据
如下图:
第二步:构建完全二叉树
第三步:构建大根堆
从 last_child/2 节点往前,每个节点与其子节点比较,按照 fixDown 操作,如下图:
第四步:pop 最大值
执行 delMax 操作,将最大值输出,然后将最后的节点编程根节点,然后执行 fixDown 操作,如下图:
参考:HEAP SORT
代码实现如下:
pq.h
1 2 3 4 5 6 7 8 9 10 | // pq.h: ADT interface for a priority queue #include <stdio.h> #include <stdlib.h> typedef struct pqRep *PQ; PQ createPQ( int size); void insertPQ(PQ q, int it); int delMaxPQ(PQ q); int isEmptyPQ(PQ q); |
pqSort.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /* pqSort.c: use a priority queue to sort an array of integers into descending order */ #include "pq.h" int main() { int a[] = {41, 2, 58, 156, 360, 81, 260, 74, 167, 13}; int length = sizeof (a)/ sizeof (a[0]); PQ q = createPQ(length); printf ( "Array: " ); for ( int i = 0; i < length; i++) { printf ( "%d " , a[i]); insertPQ(q, a[i]); } printf ( "\nSorted: " ); while (!isEmptyPQ(q)) { printf ( "%d " , delMaxPQ(q)); } putchar ( '\n' ); return EXIT_SUCCESS; } |
pqHP.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | // pqHP.c: priority queue implementation for pq.h using a heap #include "pq.h" // 'static' means these functions are for local use only static void fixDown( int *, int , int ); static void fixUp( int *, int ); // Priority queue implementation using an unordered array struct pqRep { int nItems; // actual count of Items int *items; // array of Items int maxsize; // maximum size of array }; PQ createPQ( int size) { PQ q = malloc ( sizeof ( struct pqRep)); // make room for the structure if (q == NULL) { fprintf (stderr, "out of memory\n" ); exit (0); } q->items = malloc ((size+1) * sizeof ( int )); // make room for the array if (q->items == NULL) { // size+1 because heap 1..size fprintf (stderr, "out of memory\n" ); exit (0); } q->nItems = 0; // we have no items yet q->maxsize = size; // remember the maxsize return q; // return the initial PQ } void insertPQ(PQ q, int it) { if (q == NULL) { fprintf (stderr, "priority queue not initialised\n" ); exit (1); } if (q->nItems == q->maxsize) { fprintf (stderr, "priority queue full\n" ); exit (1); } q->nItems++; // adding another item q->items[q->nItems] = it; // put the item at the end fixUp(q->items, q->nItems); // fixUp all the way to the root return ; } int delMaxPQ(PQ q) { if (q == NULL) { fprintf (stderr, "priority queue not initialised\n" ); exit (1); } if (q->nItems == 0) { fprintf (stderr, "priority queue empty\n" ); exit (1); } int retval = q->items[1]; // this is the item we want to return q->items[1] = q->items[q->nItems]; // overwrite root by last item q->nItems--; // we are decreasing heap size by 1 fixDown(q->items, 1, q->nItems); // fixDown the new root return retval; } int isEmptyPQ(PQ q) { int empty = 0; if (q == NULL) { fprintf (stderr, "isEmptyPQ: priority queue not initialised\n" ); } else { empty = q->nItems == 0; } return empty; } // fix up the heap for the 'new' element child void fixUp( int *heap, int child) { while (child>1 && heap[child/2]<heap[child]) { int swap = heap[child]; // if parent < child, do a swap heap[child] = heap[child/2]; heap[child/2] = swap; child = child/2; // become the parent } return ; } // force value at a[par] into correct position void fixDown( int *heap, int par, int len) { int finished = 0; while (2*par<=len && !finished) { // as long as you are within bounds int child = 2*par; // the first child is here if (child<len && heap[child]<heap[child+1]) { child++; // choose larger of two children } if (heap[par]<heap[child]) { // if node is smaller than this child ... int swap = heap[child]; // if parent < child, do a swap heap[child] = heap[child/2]; heap[child/2] = swap; par = child; // ... and become this child } else { finished = 1; // else we do not have to go any further } } return ; } |
Compile and run:
1 2 3 4 | prompt$ dcc pqHP.c pqSort.c prompt$ . /a .out Array: 41 2 58 156 360 81 260 74 167 13 Sorted: 360 260 167 156 81 74 58 41 13 2 |
通过array来实现ADT,就是每次通过遍历比array里面的最大值,然后输出,并由最后一个元素补位
pqUA.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | // pqUA.c: priority queue implementation for pq.h using an unordered array #include "pq.h" struct pqRep { int nItems; // actual count of Items int *items; // array of Items int maxsize; // maximum size of array }; PQ createPQ( int size) { PQ q = malloc ( sizeof ( struct pqRep)); // make room for the structure if (q == NULL) { fprintf (stderr, "out of memory\n" ); exit (0); } q->items = malloc (size * sizeof ( int )); // make room for the array if (q->items == NULL) { fprintf (stderr, "out of memory\n" ); exit (0); } q->nItems = 0; // we have no items yet q->maxsize = size; // remember the maxsize return q; // return the initial PQ } void insertPQ(PQ q, int it) { if (q == NULL) { fprintf (stderr, "priority queue not initialised\n" ); exit (1); } if (q->nItems == q->maxsize) { fprintf (stderr, "priority queue full\n" ); exit (1); } q->items[q->nItems] = it; // UNORDERED ARRAY, so put item at the end q->nItems++; // increment the 'counter' } int delMaxPQ(PQ q) { // UNORDERED, so need to linear search for max item if (q == NULL) { fprintf (stderr, "delmaxPQ: priority queue not initialised\n" ); exit (1); } if (q->nItems == 0) { fprintf (stderr, "priority queue empty\n" ); exit (1); } int *array = q->items; int last = q->nItems-1; // items occupy places 0 .. last int max = 0; // assume initially item at max=0 has largest key for ( int i = 1; i <= last; i++){ if (array[max] < array[i]){ // now compare with every other item max = i; // whenever we find a better one, update max } } int retval = array[max]; // save the max item array[max] = array[last]; // overwrite max location with last item q->nItems--; // decrease the number of items return retval; // return the max element } int isEmptyPQ(PQ q) { int empty = 0; if (q == NULL) { fprintf (stderr, "isEmptyPQ: priority queue not initialised\n" ); } else { empty = q->nItems == 0; } return empty; } |
也可以通过有序array来实现,就是在插入的过程中就进行排序
pqOA.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | // pqOA.c: priority queue implementation for pq.h using an ordered array #include "pq.h" struct pqRep { int nItems; // actual count of Items int *items; // array of Items int maxsize; // maximum size of array }; PQ createPQ( int size) { PQ q = malloc ( sizeof ( struct pqRep)); // make room for the structure if (q == NULL) { fprintf (stderr, "out of memory\n" ); exit (0); } q->items = malloc (size * sizeof ( int )); // make room for the array if (q->items == NULL) { fprintf (stderr, "out of memory\n" ); exit (0); } q->nItems = 0; // we have no items yet q->maxsize = size; // remember the maxsize return q; // return the initial PQ } void insertPQ(PQ q, int it) { if (q == NULL) { fprintf (stderr, "priority queue not initialised\n" ); exit (1); } if (q->nItems == q->maxsize) { fprintf (stderr, "priority queue full\n" ); exit (1); } int *array = q->items; int last = q->nItems; int i; for (i=0; i<last && array[i]<it; i++) { ; // find location of item == it } int j; for (j = last; j>i; j--){ // starting at last and go down to i array[j] = array[j-1]; // shift items up } array[i] = it; // now insert item 'it' at i q->nItems++; // increase the count } int delMaxPQ(PQ q) { if (q == NULL) { fprintf (stderr, "priority queue not initialised\n" ); exit (1); } if (q->nItems == 0) { fprintf (stderr, "priority queue empty\n" ); exit (1); } q->nItems--; return q->items[q->nItems]; } int isEmptyPQ(PQ q) { int empty = 0; if (q == NULL) { fprintf (stderr, "isEmptyPQ: priority queue not initialised\n" ); } else { empty = q->nItems == 0; } return empty; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)