参考资料:http://blog.csdn.net/linyunzju/article/details/7765324
本文 用最大堆来维护队列中的节点,队列用单链表表示,每个节点包含数据,而最大堆用数组表示,数组元素为节点的指针 。
本文通过在Node节点中维护一个index变量,来指示该节点在最大堆数组中的位置, 实现了O(lgN)复杂度的入队和出队操作。
在本程序中最大堆的下标从0开始,如下图:
0
/ \
1 2
/ \ / \
3 4 5 6
代码如下:
#include <stdio.h>
#include <stdlib.h>
#define MAXLEN 100
typedef struct node
{
int data;
struct node *next;
int index; //记录本node在arr中下标
}Node;
Node *arr[MAXLEN]; // 最大堆数组
Node *head = 0; //队列头指针
Node *tail = 0; //队列尾指针
int node_num=0; //队列中的节点个数
int left(int i)//返回左孩子位置
{
return 2*i+1;
}
int right(int i)//返回右孩子位置
{
return 2*i+2;
}
int parent(int i)//返回父节点的位置
{
if (node_num == 0 || i < 1)
{
return -1;
}
return (i-1)/2;
}
void EnQueue(int data)
{
int pos;
// 新建节点并赋值
Node *node =(Node *)malloc(sizeof(Node));
node->data = data;
node->next = 0;
node->index = node_num;
// 若原队列中没有节点
if (node_num == 0)
{
head = tail = node;
arr[node_num++] = node;
return;
}
// 若队列中已有节点,将tail指向node,并将node放在最大堆的末尾
arr[node_num++] = node;
tail->next = node;
tail = node;
// 执行shift_up操作,维持最大堆,在此过程中维护index值。
pos = node_num-1;
while (parent(pos) >= 0)
{
if (data <= arr[parent(pos)]->data)
break;
arr[pos] = arr[parent(pos)];
arr[pos]->index = pos;
pos = parent(pos);
}
arr[pos] = node;
arr[pos]->index = pos;
}
int DeQueue()
{
int pos;
int largest;
Node *tempNode;
int data;
// 若队列中没有节点
if (node_num == 0)
{
return -1;
}
// 将head节点删去,保存head节点在最大堆中的位置
data = head->data;
pos = head->index;
tempNode = head->next;
free(head);
arr[pos] = 0;
head = tempNode;
//队列中原来有1个节点,dequeue操作后,队列变为空。
if ( node_num == 1)
{
node_num--;
head=tail=0;
return data;
}
//删除的节点是最大堆中的最后一个节点
if (pos == node_num - 1)
{
node_num--;
return data;
}
//否则,当删除的节点不是最后一个节点时,需要调整最大堆。
//此时,我们维护的index变量派上用场了,将堆中最后一个节点放在index位置,
//并调整堆。此时可能有两种情况,分别处理。
arr[pos] = arr[node_num - 1];
arr[pos]->index = pos;
tempNode = arr[pos];
//情况一:替换来的节点值比父节点大, 执行shift_up。
if ( parent(pos) >= 0
&& arr[pos]->data > arr[parent(pos)]->data) {
while (parent(pos) >= 0)
{
if (tempNode->data <= arr[parent(pos)]->data)
break;
arr[pos] = arr[parent(pos)];
arr[pos]->index = pos;
pos = parent(pos);
}
arr[pos] = tempNode;
arr[pos]->index = pos;
node_num --;
return data;
}
//情况二:替换来的节点值比子节点小, 执行shift_down。
while(left(pos) <= node_num-1)
{
if (tempNode->data < arr[left(pos)]->data)
{
largest = left(pos);
} else {
largest = pos;
}
if ( (right(pos)<= node_num -1) && arr[largest]->data < arr[right(pos)]->data)
{
largest = right(pos);
}
if (largest != pos)
{
arr[pos] = arr[largest];
arr[pos]->index = pos;
pos = largest;
} else {
break;
}
}
arr[pos] = tempNode;
arr[pos]->index = pos;
node_num --;
return data;
}
// O(1)的时间内得到最大值元素
int maxElement()
{
if (node_num <= 0)
{
return -1;
}
return arr[0]->data;
}
void print_queue()
{
int i;
for(i=0;i< node_num;i++)
printf("%d ",arr[i]->data);
printf("\nnode_num = %d\n", node_num);
printf("max value: %d\n\n", maxElement());
}
void clear_queue()
{
int i;
for(i=0;i<node_num;i++)
{
free(arr[i]);
arr[i] = 0;
}
}
int main()
{
int n = 10;
int data[] = {12,43,54,2,66,34,22,87,8,55};
int i;
for (i=0; i<n; i++)
EnQueue(data[i]);
print_queue();
DeQueue();
DeQueue();
print_queue();
clear_queue();
}