優先佇列和堆,與priority_queue的學習筆記
今天花了一天的時間把優先佇列和堆,還有priority_queue給學習了學習,現在做下筆記。學完認識到優先佇列就是堆的一種,而priority_queue是為優先佇列準備的STL,定義與使用起來十分方便。
堆
先說堆,堆是一個二叉樹,以小根堆為例(大根堆就相反了)兒子的值一定不小於父親的值,可用陣列儲存,插入數值時先在堆的末尾插入該數值,然後不斷向上交換,將優先順序大(即數值較小的)的交換上去直到沒有大小顛倒為止。
而取出元素,是取根部,換成陣列,就是下標為零那個。刪除時,首先把堆的最後一個節點的數值複製到根節點上,並且刪除最後一個節點,然後不斷向下交換,直到沒有大小顛倒為止。如果兩個兒子都比根小,則選擇小的那個兒子進行交換
下面是根的實現例項
//堆的建立與使用 #include<iostream> using namespace std; const int MAX_N=100; int heap[MAX_N],sz=0; void push(int x) { int i=sz++; while(i>0) { int p=(i-1)/2; if(heap[p]>x) { heap[i]=heap[p]; i=p; } else break; } heap[i]=x; } int pop() { int ret=heap[0]; int x=heap[--sz]; int i=0; while(i*2+1<sz) { int a=i*2+1; int b=i*2+2; if(b<sz && heap[b]<heap[a]) a=b; if(heap[a]>=x) break; heap[i]=heap[a]; i=a; } heap[i]=x; return ret; } int main() { int i; push(1); push(3); push(2); push(5); push(6); for(i=0;i<sz;i++) { cout<<heap[i]<<endl; } cout<<"pop:"<<pop()<<endl; cout<<"pop:"<<pop()<<endl; cout<<"pop:"<<pop()<<endl; for(i=0;i<sz;i++) { cout<<heap[i]<<endl; } return 0; }
優先佇列
再說說優先佇列。
優先佇列能夠完成的就是能插入一個數值,但每次取出的數值一定是最小的(或最大的,看個人需求)。我先開始用vector容器,寫了個佇列,然後每次插入資料前的時候用 lower_bound 函式檢測要插入的位置,最後將資料插入指定的位置。當然這個時間可能用的比較長,但這是我一開始就想到並實踐的方法,優點是簡單
此處為我實現的筆記,各位看官可忽略
#include<iostream> #include<vector> #include<algorithm> using namespace std; bool cmp(int a,int b) { return a>b; } int main() { vector <int> v; vector <int>::iterator it; int n,i; cin>>n; //此處輸入即將輸入資料的個數 for(i=0;i<n;i++) { int vi; cin>>vi; it=lower_bound(v.begin(),v.end(),vi,cmp); v.insert(it,vi); } while(!v.empty()) //這樣每次尾部的函式是最小的函式 { cout<<v.back()<<" "; v.pop_back(); //每次彈出的也是尾部的函式 } cout<<endl; return 0; }
priority_queue的使用
這個是優先佇列的STL,是以堆的形式進行儲存,如果不是自己定義的資料結構,有兩種,一個是大根堆,即取出的數一定是最大的,另一個是以小根堆的定義
大根堆:priority_queue<int> max_q;
小根堆:priority_queue<int,vector<int>,greater<int> >min_q; (親測最後"greater<int> >"處空格不能少,不然編譯錯誤。原因大概是跟>>運算子發生歧義
#include<iostream>
#include<queue>
using namespace std;
int main()
{
priority_queue<int> max_q; //大根堆
priority_queue<int,vector<int>,greater<int> > min_q; //小根堆
int n,i,temp;
cin>>n;
for(i=0;i<n;i++)
{
cin>>temp;
max_q.push(temp);
min_q.push(temp);
}
cout<<endl;
//大根堆的輸出
while(!max_q.empty())
{
cout<<max_q.top()<<" ";
max_q.pop();
}
cout<<endl;
while(!min_q.empty())
{
cout<<min_q.top()<<" ";
min_q.pop();
}
cout<<endl;
return 0;
}
下面是含有自己定義的資料結構struct時,進行優先佇列使用的方法
有兩種方法。第二種方法我給註釋掉了。用第二種方法的時候別忘了將第一種方法的部分註釋掉
//優先佇列的研究2:資料結構的優先佇列方法
#include<iostream>
#include<queue>
using namespace std;
struct time
{
int hour;
int minute;
int second;
//第一種過載方法,結構體內過載,當如此過載時,優先佇列的定義方法:priority_queue<time> q;
friend bool operator < (time t1,time t2) //此處運算子過載
{
if(t1.hour==t2.hour)
{
if(t1.minute==t2.minute)
{
return t1.second<t2.second;
}
else
return t1.minute<t2.minute;
}
else
return t1.hour<t2.hour;
}
//最終的效果會是一個大根堆
};
/*第二種過載方法,結構體外過載比較函式
struct cmp{
bool operator()(time t1,time t2)
{
if(t1.hour==t2.hour)
{
if(t1.minute==t2.minute)
{
return t1.second<t2.second;
}
else
return t1.minute<t2.minute;
}
else
return t1.hour<t2.hour;
}
};
*/
int main()
{
priority_queue<time> q;
//priority_queue<time,vector<time>,cmp > q; //當使用類外過載比較函式的時候優先佇列要如此定義
int n,i;
time ti;
cin>>n;
for(i=0;i<n;i++)
{
cin>>ti.hour>>ti.minute>>ti.second;
q.push(ti);
}
while(!q.empty())
{
ti=q.top();
cout<<ti.hour<<":"<<ti.minute<<":"<<ti.second<<endl;
q.pop();
}
return 0;
}
大概就這麼多,如果日後有什麼缺少的我還會補充的