棧 隊列 堆

本文將從數組模擬和STL兩方面來簡要介紹棧、隊列和堆並同時介紹相關的簡單用法。

棧是一種能有效幫助我們臨時保存數據的數據結構,按照最後進棧的數據最先出棧(Last In First Out,LIFO,後進先出)的規則管理數據。棧是一端開口一端閉合的管道,即只能在某一端插入和刪除的特殊線性表。

1.數組

使用數組實現時,棧底位置可以設置在數組的任意一個端點,棧頂隨着元素的插入和刪除而變化,可以設定一個棧指針來指向其位置。

int stack[maxn], t=0;

進棧

  1. 檢查棧是否已滿,滿則溢出;
  2. 棧指針自增,指向進棧位置;
  3. 將進棧位置賦值爲新進棧的元素。
void push(int x)
{
	if(t==maxn) printf("Overflow\n");
	else
	{
		t++;
		stack[t] = x;
	}
}

出棧

  1. 檢查是否已爲空棧,空則下溢;
  2. 棧指針自減。
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. 尾指針自增;
  2. 若尾指針到達隊尾,則賦爲1;
  3. 判斷頭尾指針是否重合,若重合則上溢,否則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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章