本文將從數組模擬和STL兩方面來簡要介紹棧、隊列和堆並同時介紹相關的簡單用法。
棧
棧是一種能有效幫助我們臨時保存數據的數據結構,按照最後進棧的數據最先出棧(Last In First Out,LIFO,後進先出)的規則管理數據。棧是一端開口一端閉合的管道,即只能在某一端插入和刪除的特殊線性表。
1.數組
使用數組實現時,棧底位置可以設置在數組的任意一個端點,棧頂隨着元素的插入和刪除而變化,可以設定一個棧指針來指向其位置。
int stack[maxn], t=0;
進棧
- 檢查棧是否已滿,滿則溢出;
- 棧指針自增,指向進棧位置;
- 將進棧位置賦值爲新進棧的元素。
void push(int x)
{
if(t==maxn) printf("Overflow\n");
else
{
t++;
stack[t] = x;
}
}
出棧
- 檢查是否已爲空棧,空則下溢;
- 棧指針自減。
void pop()
{
if(!t) printf("Underflow\n");
else t--;
}
訪問棧頂元素
int top = stack[t];
判斷棧是否爲空
標誌:t = 0
得到棧中元素數量
棧中元素的數量即爲棧頂指針t的值。
2.STL
C++的STL中提供了棧的標準庫,使用起來更加方便快捷。使用頭文件stack
。
stack<int> s;
進棧:s.push(x);
出棧:s.pop();
訪問棧頂元素:s.top();
判斷棧是否爲空:s.empty();
得到棧中元素數量:s.size();
3.例題
https://blog.csdn.net/baidu_41248654/article/details/104663035
隊列
隊列是一個等待處理的行列,是按數據抵達的先後順序處理進行處理的數據結構,按照最先放入的元素最先被取出(First In First Out,FIFO,先進先出)的規則管理數據。
1.數組
隊列可以使用數組Q[m+1]來存儲,數組的上界m即是隊列所容許的最大容量。在隊列的運算中需設頭指針head和尾指針tail,一般情況下兩個指針的初值爲0。
int q[m+1], head=0, tail=0;
入隊(形成循環隊以克服假溢出)
假溢出:尾指針已經處理到隊尾但隊列中仍有空位置的情況。
- 尾指針自增;
- 若尾指針到達隊尾,則賦爲1;
- 判斷頭尾指針是否重合,若重合則上溢,否則Q[tail]存儲新入隊的元素。
void push(int x)
{
tail++;
if(tail == m) tail = 1;
if(tail == head) cout<<"Overflow"<<endl;
else q[tail] = x;
}
出隊
頭指針自增。
void pop()
{
head++;
}
訪問隊首元素
int front = q[head+1];
判斷隊列是否爲空(非循環隊)
標誌:head == tail
得到隊列中元素數量(非循環隊)
tail-head的值即爲隊列中元素數量。
2.STL
C++的STL中提供了隊列的標準庫,使用起來更加方便快捷。使用頭文件queue
。
queue<int> q;
入隊:q.push(x);
出隊:q.pop();
訪問隊首元素:q.front();
判斷隊列是否爲空:q.empty();
得到隊列中元素數量:q.size();
3.例題
https://blog.csdn.net/baidu_41248654/article/details/104278212
堆
堆結構是一種數組對象,它可以被視爲一棵完全二叉樹。樹中每個結點與數組中存放該結點中值的那個元素相對應。
1.數組
圖片123
設數組A的長度爲len,二叉樹的結點個數爲size,size≤len,則A[i]存儲二叉樹中編號爲i的結點值(1≤i≤size),而A[size]以後的元素並不屬於相應的堆,樹的根爲A[1],並且利用完全二叉樹的性質,我們很容易求第i個結點的父結點(parent(i))、左孩子結點(left(i))、右孩子結點(right(i))的下標了,分別爲:i/2、2i、2i+1;
更重要的是,堆具有這樣一個性質,對除根以外的每個結點i,A[parent(i)]≥A[i]。即除根結點以外,所有結點的值都不得超過其父結點的值,這樣就推出,堆中的最大元素存放在根結點中,且每一結點的子樹中的結點值都小於等於該結點的值,這種堆又稱爲“大根堆”;反之,對除根以外的每個結點i,A[parent(i)]≤A[i]的堆,稱爲“小根堆”。
插入元素
- [1] 在堆尾加入一個元素,並把這個結點置爲當前結點;
- [2] 比較當前結點和其父結點的大小:如果當前結點小於父結點則交換它們的值,並把父結點置爲當前結點,轉到[2];如果當前結點大於父結點則轉到[3];
- [3] 結束。
void put(int x)
{
int now, next;
heap[++heap_size] = x;
now = heap_size;
while(now > 1)
{
next = now>>1;
if(heap[now] >= heap[next]) break;
swap(heap[now], heap[next]);
now = next;
}
}
取出並刪除元素
- [1] 取出堆的根結點的值;
- [2] 把堆的最後一個結點(len)放到根的位置上,把根覆蓋掉,把堆的長度減一;
- [3] 把根結點置爲當前父結點father;
- [4] 如果father無兒子(father>len/2),則轉到[6],否則把father的兩個(或一個)兒子中值最小的置爲當前的子結點son,轉到[5];
- [5] 比較father與son的值,如果father<=son,轉到[6],否則,交換這兩個結點的值,把father指向son,轉到[4];
- [6] 結束。
int get() // heap[1]爲堆頂
{
int now=1, next, res=heap[1];
heap[1] = heap[heap_size--];
while(now*2 <= heap_size)
{
next = now*2;
if(next<heap_size && heap[next+1]<heap[next]) next++;
if(heap[now] <= heap[next]) break;
swap(heap[now], heap[next]);
now = next;
}
return res;
}
2.STL
C++的STL中提供了優先隊列標準庫,一般用來解決一些貪心問題,其底層是用堆來實現的。在優先隊列中,任何時刻,隊首元素一定是當前隊列中優先級最高(優先值最大)的那一個(大根堆),也可以是最小的那一個(小根堆)。使用頭文件queue。
priority_queue<int, vector<int>, greater<int> > q; // 小根堆
priority_queue<int, vector<int>, less<int> >q; // 大根堆
建立結構體類型的優先隊列需重載運算符,例如:
struct node{
int t, No;
};
priority_queue<node, vector<node> > q;
bool operator < (const node &s1, const node &s2)
{
if(s1.t != s2.t) return s1.t > s2.t;
else return s1.No > s2.No;
}
入隊:q.push(x);
出隊:q.pop();
訪問隊首元素:q.top();
判斷隊列是否爲空:q.empty();
得到隊列中元素數量:q.size();
3.例題
https://blog.csdn.net/baidu_41248654/article/details/104294322