现在的位置: 首页 > 综合 > 正文

《算法导论》学习总结——第二部分2优先级队列

2013年03月16日 ⁄ 综合 ⁄ 共 3279字 ⁄ 字号 评论关闭

      如堆一样,队列也有2种,最大优先级队列和最小优先级队列。最大优先级队列的一个应用是在一台分时计算机上进行作业调度(终于搞到点有用的),对于最大优先级队列,支持以下操作:

     1)INSERT(S,x)把元素x插入队列S

     2)MAXIMUM(S):返回S中最大元素

    3)EXTRACT-MAX(S):去掉并返回S中最大元素

 4)INCRESE-KEY(S,x,key)在x位置插入值key。

     优先级队列,用堆实现,这就是看到的必杀运用了。

    我们以82页图为例

示范程序如下:

//============================================================================
// Name        : prioity.cpp
// Author      : xia
// Version     : 1.0
// Copyright   : NUAA
// Description : 优先级队列的模拟实现
//============================================================================
#include <iostream>
#include <climits> //INT_MIN
#include <vector> //vector
#include <algorithm>//for_each
using namespace std;

int Parent(int i)
{//返回i节点的父节点
	if (i>0)
		return i/2;
	return -1;
}
void MaxHeapify(vector<int> &v ,int i ,int heap_size)
{//让A[i]在最大堆中下降,使以i为根的子树成为大顶堆
	int left=2*i; //l<-LEFT(i)
	int right = 2*i+1; //r<-RIGHT(i)
 	int largest=i;
 
 	if ( (left <= heap_size)  && (v[left] > v[i]) )
 		largest = left ;
  	else
  		largest = i;
 	if ( (right <=heap_size ) && (v[right] > v[largest]) )
 		largest = right;//从父母和自己中找出最大的
 
 	if (largest != i)
 	{
 		swap(v[i],v[largest]);//交换使i和子堆满足堆性质,不过largest为根的可能违反,递归调整
 		MaxHeapify(v,largest, heap_size);
 	} 
}
void BuildHeap(vector<int> &v)
{//建堆
	for (int i=v.size()/2 ; i > 0 ; i--)
		MaxHeapify(v,i,v.size()-1); 
}
int HeapMaximum(vector<int> A)
{ //返回堆上的最大元素
	return A[1];
}
int HeapExtractMax(vector<int> &A )
{ //去掉并返回A中最大的值
	int heap_size = A.size()-1;
	if ( heap_size <1 )
	{
		cout << " heap underflow" << endl;
		exit(EXIT_FAILURE);
	}
	int max = A[1];
	A[1] = A[heap_size];
	heap_size--; 
	A.pop_back();
	MaxHeapify(A,1 ,heap_size);
	return max;
}
void HeapIncreaseKey(vector<int> &A , int i, int key)
{ //在i处插入值为key的数,并调整堆
	if (key<A[i])
	{
		cout << " new key is smaller than current key " << endl;
		exit(EXIT_FAILURE);
	}
	A[i] = key;
	while ( (i>1) && (A[Parent(i)] < A[i]))
	{
		swap(A[i],A[Parent(i)]);
		i = Parent(i) ;
	}
}
void MaxHeapInsert(vector<int> &A , int key)
{
	A.push_back(INT_MIN); //伪代码heapsize+1,且插入负无穷
	HeapIncreaseKey(A,A.size()-1,key);//第二个参数实际为堆大小
}

template <class T> 
class Print 
{
 public: 
	 void operator () (T& t) 
	 {
		 cout << t << " "; 
	 }
};

const int heap_size = 10; //这里假设元素为10个

int main()
{
	int temp[heap_size]={16,14,10,8,7,9,3,2,4,1};
	vector<int> v(temp+0,temp+heap_size);

	Print<int> print;
	v.insert(v.begin(),0);//插入个0,切合伪代码

	BuildHeap(v); //虽然我们的数组顺序已经符合堆,不过常理还是要先建堆

	cout << "初始堆V " << endl;
	for_each(v.begin()+1,v.end(),print);//遍历输出
	cout << endl<< endl;

	cout <<"插入个试试 " << endl;
	HeapIncreaseKey(v,9,15);//p82图
	for_each(v.begin()+1,v.end(),print);
	cout << endl << endl;

	cout << "提取个" << endl;
	cout << "max = " << HeapExtractMax(v) << endl;
	for_each(v.begin()+1,v.end(),print);
	cout << endl << endl ;

	cout << "再提取个" << endl;
	cout << "max = " << HeapExtractMax(v) << endl;
	for_each(v.begin()+1,v.end(),print);
	cout << endl << endl;

	cout << "插入个" << endl;
	MaxHeapInsert(v,20);
	for_each(v.begin()+1,v.end(),print);
	cout << endl << endl;

	return 0;
}

运行结果如下:

     程序各部分的说明在源代码中,添加说明如下:

    1、 为了更接近伪代码,我们将vector的0位置不用,于是left[i]=2*i,right[i]=2*i+1;

    2、虽然我们的初始数组已经符合堆概念,不过这只是巧合,对于任意数组,我们应该首先对其建堆,BuildHeap
    看起来,第二步插入,只是如书82页的图,对优先级进行了改变,而第五步的插入数,则更像是新到一个作业,很像作业调度吧?哈哈,堆,想不到也是高级货。。。

     抄书上一句话,一个堆,可以在O(lgn)时间内,支持大小为n的集合上的任意优先队列操作。

     看到MAX-HEAP-INSERT过程,有没有很眼熟?根据思考题6.1,其实我们建堆的时候,可以用MaxHeapInsert过程,不够这样建堆,感觉跟插入排序没什么两样了。

过程如下:

    

void BuildMaxHeap(vector<int> &v)
{
     v.clear();
     for (int i=0 ; i<v.size() ; i++)
           MaxHeapInsert(A,v[i]);
}

      第六章的一些想法:

      关于堆排序,个人觉得, 其实也是类似选择排序,每次选出最大的,只是比较都是每个子,左右三个节点进行,排序中规模会减少,虽然这个与选择是一样,不过堆引入递归(插入也有递归,其实也快不了多少,所以堆排序快的因素不是递归),而且堆有划分的想法,对每个子堆分别进行。如同快排的划分,使得上下半部分不用进行比较,从而与选择排序比大大减少了比较次数。

      关于优先级队列,以前知道队列调度,虽然可以用队列进行调度,不过借助堆这样的结构去组织,清晰的画出图之后,发现理解会更深刻一点,也更形象。

     

       菜鸟goes on ~~~

抱歉!评论已关闭.