优先队列
采用二叉堆实现,因其为完全二叉树结构,故堆中的节点可以用数组来存储,访问也可以使用数组下标而代替指针;
优先队列的插入和删除操作的最坏时间复杂度均为O(logN),而其队列中的最小值(或最大值)总是处于队列
前端,如果一直删除队列中的最小元素知道队列空,即可得到一个排序的数组,故优先队列用于排序的时间复杂度为O(NlogN)
C语言实现:
将数组的第一个元素利用来保存来保存当前队列中的元素个数,这样i, 2i 和2i+1即分别表示父节点下标、左子节点下标和右子节点下标:
而根据堆序性,处于父节点的元素
总是大于其两个子节点(最大堆)或者
总小于其两个子节点(最小堆),下面实现的最小堆,故最小的元素
总处于堆顶,而插入和删除操作也均是根据堆序性去调整堆中数据。
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
typedef struct pri_queue_type pri_queue_t;
pri_queue_t *initialize(int capacity);
void destroy(pri_queue_t *priq);
int is_empty(pri_queue_t *priq);
int is_full(pri_queue_t *priq);
void insert(pri_queue_t *priq, int x);
int get_min(pri_queue_t *priq);
void delete_min(pri_queue_t *priq);
struct pri_queue_type {
int capacity;
int *elems;/*数组第一个元素来表示队列中当前元素个数*/
};
#define PARENT(i) ((i)>>1)//下标为i的节点的父节点下标i/2
#define LCHILD(i) ((i)<<1)//下标为i的节点的左儿子下标2*i
int main(int argc, char *argv[])
{
pri_queue_t *priq;
#define CAPACITY 50
priq = initialize(CAPACITY);
srand(time(NULL));
int i;
for (i = 0; i < CAPACITY; i ++) {
insert(priq, rand()%100);
}
for (i = 0; i < CAPACITY; i ++) {
printf("%3d", priq->elems[i+1]);
}
printf("\ndelete:\n");
for (i = 0; i < CAPACITY; i ++) {
printf("%3d", get_min(priq));
delete_min(priq);
}
return 0;
}
pri_queue_t *initialize(int capacity)
{
if (capacity < 1)
return NULL;
pri_queue_t *priq;
priq = (pri_queue_t *)malloc(sizeof(pri_queue_t));
assert(priq != NULL);
priq->capacity = capacity;
priq->elems = (int *)malloc(sizeof(int) * capacity);
assert(priq->elems != NULL);
priq->elems[0] = 0;
return priq;
}
void destroy(pri_queue_t *priq)
{
if (NULL == priq)
return;
free(priq->elems);
free(priq);
}
int is_empty(pri_queue_t *priq)
{
return (0 == priq->elems[0]);
}
int is_full(pri_queue_t *priq)
{
return (priq->elems[0] == priq->capacity);
}
void insert(pri_queue_t *priq, int x)
{
if (NULL == priq)
return;
if (is_full(priq)) {
printf("full.\n");
return;
}
int i = ++ priq->elems[0];
for (; i!=1 && priq->elems[PARENT(i)]>x; i = PARENT(i)) {
priq->elems[i] = priq->elems[PARENT(i)];
}
priq->elems[i] = x;
}
int get_min(pri_queue_t *priq)
{
return priq->elems[1];
}
void delete_min(pri_queue_t *priq)
{
assert(priq != NULL);
if (is_empty(priq)) {
printf("empty.\n");
return;
}
int lastelem = priq->elems[priq->elems[0]--];
int i, child;
for (i = 1; LCHILD(i) <= priq->elems[0]; i = child) {
child = LCHILD(i);
if (child!=priq->elems[0] && priq->elems[child]>priq->elems[child+1])
++ child;
if (lastelem > priq->elems[child])
priq->elems[i] = priq->elems[child];
else
break;
}
priq->elems[i] = lastelem;
}
python 实现:
和上面略有不同的是,没有指定队列的capacity
class priority_queue:
def __init__(self):
self.priq = [0]
def is_empty(self):
return 0==self.priq[0]
def min(self):
assert False == self.is_empty()
return self.priq[1]
def insert(self, x):
self.priq[0] += 1
self.priq.append(x)
i = self.priq[0]
while i>1 and self.priq[i>>1]>x:
self.priq[i] = self.priq[i>>1]
i = i>>1
self.priq[i] = x
def delete_min(self):
assert False == self.is_empty()
last_index = self.priq[0]
self.priq[0] -= 1
last_element = self.priq[last_index]
i = 1
while (i<<1)<=self.priq[0]:
child = i<<1
if child!=self.priq[0] and self.priq[child]>self.priq[child+1]:
child += 1
if last_element > self.priq[child]:
self.priq[i] = self.priq[child]
else:
break
i = child
self.priq[i] = last_element
def main():
import random
q = priority_queue()
for i in random.sample([j for j in range(1000)], 50):
q.insert(i)
print 'priority queue:\n', q.priq[1:]
print 'delete:'
while False == q.is_empty():
print q.min(),
q.delete_min()
#q.delete_min()
if __name__ == '__main__':
main()