索引优先队列
上篇讲述了优先队列,一种能够快速访问最大元素或最小元素的数据结构,但是考虑这样一种情况,公司按姓名录入员工信息,并按照薪水加入了优先队列,某员工薪水需要更改,假设薪水排名为n,那么我们需要怎样操作呢?首先将前n名员工出列,然后改正第n名薪水,最后将这n名员工入列,操作太复杂,不符合程序员追求性能(懒)的特性,于是想到将优先队列的元素加一个索引,可以随机访问.这种加入索引的优先队列就叫做索引优先队列.
用c++构造索引优先队列如下:
类构造
class IndexPriorQueue{
private:
int index;//the num of items
int size;//capacity
int* pq;//index binaryheap
int* qp;//qp[pq[i]]=pq[qp[i]]=i
T* item;//item array;
public:
IndexPriorQueue(int qsize){//constructor function
size=qsize;
index=0;
pq=new int[size+1];
qp=new int[size+1];
item=new T[size+1];
for(int i=0;i<size+1;i++)
qp[i]=-1;
}
void insert(int k,T v){
if(contain(k)){
cout<<"index is already in queue"<<endl;
return;
}
//cout<<"insert"<<endl;
item[k]=v;
pq[++index]=k;
qp[k]=index;
swim(index);
}
bool contain(int k){
return qp[k]!=-1?1:0;
}
void deleteat(int k){
int j=qp[k];
pq[j]=pq[index];
index--;
swim(j);
sink(j);
qp[k]=-1;
}
T delmax(){
int k=pq[1];
T max=item[pq[1]];
pq[1]=pq[index--];
sink(1);
qp[k]=-1;
return max;
}
void swim(int j){
while(j>1){
if(less(j/2,j)){
exch(j/2,j);
j=j/2;
}else{
break;
}
}
}
void sink(int j){
while(2*j<=index){
int k=2*j;
if(k<index&&less(k,k+1))
k++;
if(less(j,k))
exch(j,k);
else
break;
j=k;
}
}
bool less(int i,int j)
{
return item[pq[i]]<item[pq[j]]?1:0;
}
void exch(int m,int n){
int temp=pq[m];
pq[m]=pq[n];
pq[n]=temp;
qp[pq[m]]=m;
qp[pq[n]]=n;
}
void display(){
cout<<"item:";
for(int i=1;i<size+1;i++){
cout<<item[i]<<" ";
}
cout<<endl;
cout<<"pq:";
for(int i=1;i<size+1;i++){
cout<<pq[i]<<" ";
}
cout<<endl;
cout<<"qp:";
for(int i=1;i<size+1;i++){
cout<<qp[i]<<" ";
}
cout<<endl;
}
};
其中,每次插入值时,构造堆比较的是元素值的大小,然后索引会标记元素值,这样可以通过索引非常方便的访问元素.
测试代码
int main(){
cout<<"before insert:"<<endl;
IndexPriorQueue<char> ipq(10);
ipq.display();
ipq.insert(1,'a');
ipq.insert(2,'d');
ipq.insert(3,'c');
ipq.insert(5,'z');
ipq.insert(6,'x');
cout<<"after insert:"<<endl;
ipq.display();
cout<<"delmax:";
cout<<ipq.delmax()<<endl;;
ipq.display();
ipq.insert(5,'y');
ipq.display();
ipq.deleteat(6);
cout<<"deleteat";
ipq.display();
return 0;
}