队列中取最大值的最大堆实现--编程之美 3.7

参考资料: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();
		
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值