Fork me on GitHub

数据结构与算法——堆 的优先队列

操作系统内核作业调度是优先队列的一个应用实例,它根据优先级的高低而不是先到先服务的方 式来进行调度;

 

 如果最小键值元素拥有最高的优先级,那么这种优先队列叫作升序优先队列(即总是先删除最小 的元素),类似的,如果最大键值元素拥有最高的优先级,那么这种优先队列叫作降序优先队列 (即总是先删除最大的元素);由于这两种类型是完全对称的,所以只需要关注其中一种,如升 序优先队列.

 

优先队列算法实现:

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define DEFAULT_CAPCITY 128
  6 #define isLess(a,b) (a<b)
  7 
  8 typedef int DataType;
  9 
 10 typedef struct _PriorityQueue 
 11 {
 12     DataType *arr;        //存储堆元素的数组
 13     int size;            //当前已存储的元素个数
 14     int capacity;        //当前存储的容量
 15 }PriorityQueue;
 16 
 17 bool init(PriorityQueue &pq, int *orginal, int size);
 18 bool push(PriorityQueue &pq, DataType value);
 19 bool pop(PriorityQueue &pq, DataType &value);
 20 bool isEmpty(PriorityQueue &pq);
 21 bool isFull(PriorityQueue &pq);
 22 void destroy(PriorityQueue &pq);
 23 static void build(PriorityQueue &pq);
 24 static void adjustDown(PriorityQueue &pq, int index);
 25 static void adjustUp(PriorityQueue &pq, int index);
 26 
 27 /*初始化优先队列*/
 28 bool init(PriorityQueue &pq, DataType *orginal, int size) 
 29 {
 30     int capacity = DEFAULT_CAPCITY>size ? DEFAULT_CAPCITY : size;
 31     pq.arr = new DataType[capacity];
 32     if (!pq.arr) return false;
 33     pq.capacity = capacity;
 34     pq.size = 0;
 35     
 36     //如果存在原始数据则构建最大堆
 37     if(size > 0)
 38     {
 39         //方式一: 直接调整所有元素
 40         memcpy(pq.arr, orginal, size*sizeof(int));
 41         pq.size = size;
 42         //建堆
 43         build(pq);
 44     }
 45     return true;
 46 }
 47 
 48 /*销毁优先级队列*/
 49 void destroy(PriorityQueue &pq)
 50 {
 51     if(pq.arr) delete[] pq.arr;
 52 }
 53 
 54 /*优先队列是否为空*/
 55 bool isEmpty(PriorityQueue &pq)
 56 {
 57     if(pq.size<1) return true;
 58     return false;
 59 }
 60 
 61 /*优先队列是否为满*/
 62 bool isFull(PriorityQueue &pq)
 63 {
 64     if(pq.size<pq.capacity) return false;
 65     return true;
 66 }
 67 
 68 int size(PriorityQueue &pq)
 69 {
 70     return pq.size;
 71 }
 72 
 73 /* 从最后一个父节点(size/2-1 的位置)逐个往前调整所有父节点(直到根节
 74 点), 确保每一个父节点都是一个最大堆,最后整体上形成一个最大堆 */
 75 void build(PriorityQueue &pq) 
 76 {
 77     int i;
 78     for (i = pq.size / 2 - 1; i >= 0; i--) 
 79     {
 80         adjustDown(pq, i);
 81     }
 82 }
 83 
 84 /*将当前的节点和子节点调整成最大堆*/
 85 void adjustDown(PriorityQueue &pq, int index)
 86 {
 87     DataType cur = pq.arr[index];        //当前待调整的节点
 88     int parent, child;
 89     
 90     /*判断否存在大于当前节点子节点,如果不存在 ,则堆本身是平衡的,不需要调整;
 91     如果存在,则将最大的子节点与之交换,交换后,如果这个子节点还有子节点,则要继续
 92     按照同样的步骤对这个子节点进行调整*/
 93     for (parent = index; (parent * 2 + 1)<pq.size; parent = child) 
 94     {
 95         child = parent * 2 + 1;
 96         
 97         //取两个子节点中的最大的节点
 98         if (((child + 1)<pq.size) && isLess(pq.arr[child], pq.arr[child + 1])) 
 99         {
100             child++;
101         }
102         
103         //判断最大的节点是否大于当前的父节点
104         if (isLess(pq.arr[child], cur)) 
105         {
106             //不大于,则不需要调整,跳出循环
107             break;
108         }
109         else
110         {
111             //大于当前的父节点,进行交换,然后从子节点位置继续向下调整
112             pq.arr[parent] = pq.arr[child];
113             pq.arr[child] = cur;
114         }
115     }
116 }
117 
118 /*将当前的节点和父节点调整成最大堆*/
119 void adjustUp(PriorityQueue &pq, int index) 
120 {
121     if(index<0 || index >= pq.size)
122     {
123         //大于堆的最大值直接 return
124         return;
125     }
126     while(index>0)
127     {
128         DataType temp = pq.arr[index];
129         int parent = (index - 1) / 2;
130         if(parent >= 0)
131         {
132             //如果索引没有出界就执行想要的操作
133             if( isLess(pq.arr[parent], temp) )
134             {
135                 pq.arr[index] = pq.arr[parent];
136                 pq.arr[parent] = temp;
137                 index = parent;
138             }
139             else
140             {
141                 //如果已经比父亲小 直接结束循环
142                 break;
143             }
144         }
145         else
146         {
147             //越界结束循环
148             break;
149         }
150     }
151 }
152 
153 /* 删除优先队列中最大的节点,并获得节点的值*/
154 bool pop(PriorityQueue &pq, DataType &value) 
155 {    
156     if (isEmpty(pq)) return false;
157     value = pq.arr[0];
158     pq.arr[0] = pq.arr[--pq.size];
159     
160     //heap.arr[0] = heap.arr[heap.size-1];
161     //heap.size--;
162     adjustDown(pq, 0);            // 向下执行堆调整
163     return true;
164 }
165 
166 /*优先队列中插入节点*/
167 bool push(PriorityQueue &pq, DataType value) 
168 {
169     if (isFull(pq)) 
170     {
171         fprintf(stderr, "优先队列空间耗尽!\n");
172         return false;
173     }
174     int index = pq.size;
175     pq.arr[pq.size++] = value;
176     adjustUp(pq, index);
177     return true;
178 }
179 
180 int main(void) 
181 {
182     PriorityQueue pq;
183     int task[] = { 1, 2, 3, 87, 93, 82, 92, 86, 95 };
184     int i = 0;
185     
186     if(!init(pq, task, sizeof(task)/sizeof(task[0])))
187     {
188         fprintf(stderr, "初始化优先队列失败!\n");
189         exit(-1);
190     }
191     
192     for (i = 0; i<pq.size; i++) 
193     {
194         printf("the %dth task:%d\n", i, pq.arr[i]);
195     }
196     
197     //堆中插入优先级为 88 的任务
198     push(pq, 88);//堆中元素出列
199     printf("按照优先级出列:\n");
200     DataType value;
201     
202     while( pop(pq, value))
203     {
204         printf(" %d\n", value);
205     }
206     destroy(pq);
207     
208     system("pause");
209     return 0;
210 }

 

posted @ 2020-10-18 20:28  索智源  阅读(116)  评论(0编辑  收藏  举报