小根堆实现优先级队列
优先级队列操作一个初始为空的元素集合。提供两种基本操作,将一个数插入优先级队列和在优先级队列中取出一个优先级最高的数。在这里数字为正整数且小的有高的优先级。
实现优先级队列固然可以用一个有序或无序的数组来实现。对于有序的情况来说,取出一个数的时间复杂度为O(1)而插入一个数为O(n);对于无序的情况来说,插入一个数为O(1),而取出一个数为O(n)。当进行n步对优先级队列操作时时间复杂度为O(n2)。这样的效率对于百万级的数据量来说是不可想像的。
为了折衷可以找一种介于有序与无序之间的数据结构------小根堆。小根堆在整体内不保证有序,但保证与孩子节点之间是有序的,也就是都要小于孩子节点。而对堆的插入与删除操作的时间复杂度为O(lgn)所以对于大数据量来说实现优先级队列来说是可行的。
在以下的实现中,有两个函数,insert_elem与extract_max。里面核心的是对堆的两种调整方法liftup与liftdown,分别将一个新插入的元素调整到正确的位置;从根将一个数据调整到正确的位置。
以下给了一个C实现 ,主要有test.cpp、priorityqueue.h、priorityqueue.cpp
priorityqueue.h #pragma once #ifndef PRIORITYQUEUE_H #define PRIORITYQUEUE_H #include <stdio.h> #define MAXSIZE 100 #define EMPTYELEM -1 typedef struct priorityqueue{ int queuesize; //这里多出一个元素,为了计算方便一切从数组1位置开始 int pq[MAXSIZE + 1]; }sctpq,* psctpq; /************************************************* Function: initqp(psctpqf); Description: 对优先级队列进行初始化 Input: Arg1: pqp 优先级队列结构的指针 Return: void *************************************************/ void init_pq(psctpq pqp); /************************************************* Function: insert_elem Description: 向优先级队列中插入数据 Input: Arg1: 要插入的数据 Return: void *************************************************/ void insert_elem(psctpq pqp, int elem); /************************************************* Function: extract_max Description: 返回队列中优先级最高的数据 Input: void Return: 返回的最高优先级最据 *************************************************/ int extract_max(psctpq pqp); int get_pq_size(psctpq pqp); /************************************************* Function: sift_up Description: 将新插入的最尾端的节点向上调整 Input: 优先级队列 Return: void *************************************************/ void sift_up(psctpq pqp); /************************************************* Function: sift_down Description: 将新第一个元素从队列中移除后,对小根堆进行调整成为新堆 Input: 优先级队列 Return: void *************************************************/ void sift_down(psctpq pqp); /************************************************* Function: find_left_child Description: 找到给定堆中节点的左孩子 Input: Arg1: 当前的节点位置 Return: 左孩子的位置,如果没有了就返回-1 *************************************************/ int find_left_child(int pos, psctpq pqp); /************************************************* Function: find_right_child Description: 找到给定堆中节点的右孩子 Input: Arg1: 当前的节点位置 Return: 右孩子的位置,如果没有了就返回-1 *************************************************/ int find_right_child(int pos, psctpq pqp); /************************************************* Function: find_parent Description: 找到给定堆中节点的亲人节点 Input: Arg1: 当前的节点位置 Return: 当前节点的亲人的位置,如果是根节点就返回-1 *************************************************/ int find_parent(int pos, psctpq pqp); void swap(int destpos, int originpos, int* a); void show(psctpq pqp); void min_heapify(psctpq pqp, int pos); #endif
1 priorityqueue.cpp 2 3 4 #include "priorityqueue.h" 5 6 void init_pq(psctpq pqp) 7 { 8 int i; 9 pqp->queuesize = 0; 10 for (i = 0; i != MAXSIZE; i++) 11 pqp->pq[i] = EMPTYELEM; 12 } 13 14 void insert_elem(psctpq pqp, int elem) 15 { 16 if (pqp->queuesize > MAXSIZE) 17 { 18 printf("max size overflow!\n"); 19 return; 20 } 21 pqp->queuesize ++; 22 pqp->pq[pqp->queuesize] = elem; 23 sift_up(pqp); 24 } 25 26 int extract_max(psctpq pqp) 27 { 28 if (pqp->queuesize == 0) 29 { 30 printf("empty priority queue\n"); 31 return -1; 32 } 33 int rtval = pqp->pq[1]; 34 pqp->pq[1] = pqp->pq[pqp->queuesize]; 35 pqp->pq[pqp->queuesize] = 0; 36 pqp->queuesize --; 37 sift_down(pqp); 38 return rtval; 39 } 40 41 void sift_up(psctpq pqp) 42 { 43 int parentpos; 44 int currentpos; 45 //只有一个元素不用调整 46 if (pqp->queuesize == 1) 47 return; 48 else 49 { 50 parentpos = find_parent(pqp->queuesize, pqp); 51 currentpos = pqp->queuesize; 52 //数小的,优先级高,与亲节点的位置交换 53 while (pqp->pq[parentpos] > pqp->pq[currentpos] && parentpos != -1) 54 { 55 swap(parentpos, currentpos, pqp->pq); 56 currentpos = parentpos; 57 parentpos = find_parent(currentpos, pqp); 58 } 59 } 60 } 61 62 void sift_down(psctpq pqp) 63 { 64 min_heapify(pqp, 1); 65 } 66 67 void min_heapify(psctpq pqp, int pos) 68 { 69 int* a = pqp->pq; 70 int lpos, rpos; 71 lpos = find_left_child(pos, pqp); 72 rpos = find_right_child(pos, pqp); 73 //没有孩子节点到叶子节点时返回 74 if(lpos == -1) 75 return; 76 //当没有右孩子时 77 if(rpos == -1) 78 { 79 if(a[pos] <= a[lpos]) 80 return; 81 else 82 { 83 swap(pos, lpos, a); 84 min_heapify(pqp, lpos); 85 } 86 } 87 //左右孩子都有 88 else 89 { 90 //根最小 91 if (a[pos] <= a[lpos] && a[pos] <= a[rpos]) 92 return; 93 //左最小 94 else if (a[lpos] <= a[rpos]) 95 { 96 swap(lpos, pos, a); 97 min_heapify(pqp, lpos); 98 } 99 //右最小 100 else 101 { 102 swap(rpos, pos, a); 103 min_heapify(pqp, rpos); 104 } 105 } 106 } 107 108 int find_left_child(int pos, psctpq pqp) 109 { 110 int leftchildpos; 111 if(pos <= 0 || pos > pqp->queuesize) 112 return -1; 113 leftchildpos = pos << 1; 114 if (leftchildpos > pqp->queuesize) 115 return -1; 116 else return leftchildpos; 117 } 118 119 int find_right_child(int pos, psctpq pqp) 120 { 121 int rightchildpos; 122 if(pos <= 0 || pos > pqp->queuesize) 123 return -1; 124 rightchildpos = (pos << 1) + 1; 125 if (rightchildpos > pqp->queuesize) 126 return -1; 127 else return rightchildpos; 128 } 129 130 int find_parent(int pos, psctpq pqp) 131 { 132 int parentpos; 133 if(pos <= 0 || pos > pqp->queuesize) 134 return -1; 135 parentpos = pos >> 1; 136 if (parentpos < 1) 137 return -1; 138 else return parentpos; 139 } 140 141 void swap(int destpos, int originpos, int* a) 142 { 143 int buffer = a[destpos]; 144 a[destpos] = a[originpos]; 145 a[originpos] = buffer; 146 } 147 148 void show(psctpq pqp) 149 { 150 int i = 0; 151 int currentsize = pqp->queuesize; 152 if (currentsize == 0) 153 { 154 printf("empty queue\n"); 155 return; 156 } 157 printf("-------------current queue is-----------------\n"); 158 for (i; i != currentsize; i++) 159 printf("%d ", pqp->pq[i + 1]); 160 printf("\n"); 161 printf("----------------------------------------------\n"); 162 }
test.cpp #include "priorityqueue.h" #include <stdlib.h> #include <stdio.h> void main() { int i; int choice = 5; sctpq priorityqueue; init_pq(&priorityqueue); printf("priority queue init complete\n"); printf("input a selection :\n"); printf("1 to show the content of this priority queue\n"); printf("2 to input a number into the priority queue\n"); printf("3 to get a number from the priority queue\n"); printf("0 exit\n"); while (choice != 0) { printf("****tap in your choice****\n"); scanf("%d", &choice); switch (choice) { case -1: return; case 1: show(&priorityqueue); break; case 2: printf("****tap in your number****\n"); scanf("%d", &i); insert_elem(&priorityqueue, i); break; case 3: i = extract_max(&priorityqueue); if (i != -1) printf("the largest priority number is %d\n", i); break; } } }

浙公网安备 33010602011771号