【数据结构】优先队列和堆

优先队列(priority queue)

对于一般的队列是在队列的尾部添加数据,在头部删除,以便先进先出。

而优先队列中的每个元素都有一个优先级,每次将一个元素放入队列中,而每次出队时都是将优先级最大的那个元素出队,称为高进先出(largest-in,first-out)。

优先队列必须实现以下几个操作

1.入队(push):将一个元素放入队列中。

2.出队(pop):将优先级最高的元素从队列中删除。

要实现上面的操作可以维护一个有序的链表。每次插入数据时维护整个链表有序,即使用插入法,每次出队的操作只需要删除链表最前面的元素。

这么做的话入队操作的复杂度是O(n),出队是O(1),综合复杂度为O(n)。

接下来要介绍的是O(logn) 的数据结构——二叉堆。

给定一棵完全二叉树,该树的每个节点的优先级大于该节点的所有孩子节点的优先级。易知,根节点将是优先级最高的节点。

要用二叉堆来实现优先队列,必须完成的两个操作:

1.入队(push):对于一棵空的二叉堆,只需要将入堆的元素加入根节点即可。对于一般情况,我们将该元素直接加入完全二叉树的一个位置,该位置是指将这个位置加入该完全二叉树,这个树仍然是完全二叉树的那个点。之后将这个元素和他的父节点比较,若优先级大于该父节点,则与父节点交换位置,再将新插入的这个元素再和它的新父节点比较,直到它没有父节点或有一个父节点优先级大于它为止。

2.出队(pop):要拿出该完全二叉树的根节点,之后要维护剩下的节点满足二叉堆的性质。

在讲这个操作之前,我们先定义一个新的操作——假设某节点的左右两棵子树都满足堆的性质,要将整个树也变成一个堆。我们把该操作称为筛选(sift)。对于筛选算法我们需要将根节点和两个子节点比较,若根节点的优先级最大,则已经调整完成,否则将两个子节点中较大的那个和根节点进行交换,此时根节点将是最大的元素了,然后跟踪被交换的那个孩子节点的位置,继续做如上的调整,直到调整结束。

对于出队操作,删除根节点的元素,并将该二叉堆的最后一个元素(所谓最后一个元素是指将该元素从完全二叉树删除,该二叉树仍然是完全二叉树的那个元素)放到根节点的位置,然后对该树进行筛选操作。

 

一般的来讲,堆可以轻易地用数组实现,假设数组编号为1的元素是根节点,那么2和3分别是它的左右节点。对于一个数组编号为i(i>=1)的节点,他的左右节点分别为i*2和i*2+1。

要将一个数组中的n个元素(编号从1到n)直接变成堆,可以用以下操作:for(i=n/2;i>=1;i--) sift(以编号为i的节点为根节点)。这是因为超过n/2的那些节点都是叶子节点,满足堆的性质,其他节点从下往上依次进行sift操作就完成的堆的建立。

 1 #include<stdio.h>
 2 /*r[0].fix为堆的长度*/
 3 typedef int elemtype;
 4 typedef struct node
 5 {
 6     elemtype data;
 7     int fix;
 8 }HeapNode;
 9 HeapNode out(HeapNode r[],int s)/*r[s]出堆*/
10 {
11     int i,j;
12     HeapNode item;
13     item=r[s];/*数据暂存*/
14     r[s]=r[r[0].fix];/*最后一个数据放入要出堆的元素的位置上*/
15     r[0].fix--;/*长度减一*/
16     sift(r,s,r[0]);
17     return item;
18 }
19 void in(HeapNode r[],HeapNode item)/*入堆*/
20 {
21     int i;
22     for(i=r[0].fix+1;i>1;i/=2)
23     {
24         if(item.fix</*>*/r[i/2].fix) r[i]=r[i/2];
25         else break;
26     }
27     r[i]=item;
28     r[0].fix++;
29 }
30 void sift(HeapNode r[],int s,int t)/*筛选成小顶堆算法*/
31 {/*r[s...t]中的记录除r[s]外均满足堆的特性*/
32     int i,j;
33     HeapNode item;
34     item=r[s];
35     i=s;
36     j=2*i;
37     while(j<=r[0].fix)
38     {
39         if(j+1<=r[0].fix&&r[j+1].fix</*>*/r[j].fix) j++;
40         if(item.fix>/*<*/r[j].fix){r[i]=r[j];i=j;j=2*i;}
41         else break;
42     }
43     r[i]=item;
44 }
45 /*
46 初始堆的建立:
47 for(i=n/2;i>=1;--) sift(r,i,n);
48 */
49 /*堆排序*/
50 /*大顶堆完成升序,小顶堆完成降序*/
51 void Heat_sort(long r[],int n)
52 {
53     int i;
54     long item;
55     for(i=n/2;i>=1;i--) sift(r,i,n);/*初始堆的建立*/
56     for(i=n;i>=2;i--)
57     {
58         item=r[i];
59         r[i]=r[1];
60         r[1]=item;
61         sift(r,1,i-1); /*大顶堆完成升序,小顶堆完成降序*/
62     }
63 }

posted on 2014-07-18 13:21  T^T  阅读(1046)  评论(0编辑  收藏  举报

导航