實現pop push min操作時間複雜度爲O(1)的棧結構

要求:實現一個棧結構 使得pop push min(獲得棧中最小元素)操作的時間複雜度爲O(1)
要實現min函數複雜度爲O(1) 肯定不能遍歷彈入的數據也不能簡單維護一個小頂堆(小頂堆的維護需要lg(n)時間)
這個時候可以利用棧先進後出的特性:

考慮2 4 3 1 四個依次入棧的數字。在我們維護的min數據中,我們不需要保存1 2 3 4, 事實上,由於棧只能按照1 3 4 2的順序出棧,4和3永遠也不會成爲最小的數。也就是說,我們在維護min數據時,只需在遇到一個新的最小數據(即比當前的最小數據更小或相等)時,我們就將遇到的最小數據放在當前的最小數據前面(這個數據結構可用棧來維護)。這樣我們在以上入棧序列2 4 3 1中,先保存最小數據2 遇到4 3時不改變,遇到1時,將1 放在2的前面。這樣在彈出序列1 3 4 2時,如果彈出的數據是當前最小數據,我們就將該數據在min維護的數據結構中刪除掉,例如在彈出1時,min序列就只剩下2,而由於2永遠在3 4之後彈出,因此它理所當然在彈出它本身之前是最小的。另外還要注意重複最小數,比如入棧序列1 3 2 1。在彈出1之後,最小元素仍然是1,也就是說,最小棧在遇到與當前最小元素相等的元素時,也應該更新。


本例中min數據結構也用棧來維護。棧頂元素就是當前元素主棧中的最小元素

#include<iostream>
using namespace std;

class Stack
{
	//定義內部棧結構 用於構建正常數據棧和最小數據棧
	typedef struct _stack 
	{
		int* pElem;	//指向元素數據的指針
		int size;	//棧的最大容量
		int top;	//棧的當前棧頂位置
		_stack(int n):size(n)
		{
			top = 0;
			pElem = new int[size];
		}
		~_stack()
		{
			delete []pElem;
			pElem = NULL;
		}        
	}stack;

public:
	//構造時,初始化正常棧和最小數據棧
	Stack(int n):s(n), minstack(n)
	{
		
	}

	bool pop(int* e)
	{
		//判斷棧空
		if (s.top == 0)
			return false;

		int value = s.pElem[--s.top];
		//判斷將要彈出的是否是最小元素 如果是 則更新最小元素棧
		if (value == minstack.pElem[minstack.top-1])
			--minstack.top;

		*e = value;
		return true;
	}

	bool push(int value)
	{
		//判斷棧滿
		if (s.top == s.size)
			return false;

		//如果當前最小元素棧爲空或者要壓入的元素小於等於當前最小元素 則壓入
		//這裏不需要擔心最小棧溢出 因爲前面已經判斷並且top==0必須放在||前面 否則top==0時訪問top-1會越界
		//注意這裏必須是<=而不能是= 比如1 2 3 1 當1彈出時,最小元素仍然是1 因此minstack裏面應該有兩個1  
		if (minstack.top==0 || value<=minstack.pElem[minstack.top-1])
			minstack.pElem[minstack.top++] = value;

		s.pElem[s.top++] = value;
		return true;
	}

	//取最小元素 直接是最小數據棧頂元素
	bool min(int *pmin)
	{
		if (minstack.top == 0)
			return false;

		*pmin = minstack.pElem[minstack.top-1];
		return true;
	}
private:
	stack s;
	stack minstack;
};
void main()
{
	Stack s(5);
	s.push(9);
	s.push(7);
	s.push(10);
	s.push(5);
	s.push(8);
	cout<<"壓入序列9 7 10 5 8"<<endl;
	cout<<"彈出序列"<<endl;
	int v;
	while (s.pop(&v))
	{
		cout<<"pop  "<<v<<"\t";
		if (s.min(&v))
			cout<<"min value : "<<v<<endl;
		else
			cout<<"there is no min value!"<<endl;
	}
	return ;
}


總結: 本題的關鍵點就在於理解棧結構,由於其先進後出的特性,使得在一個更小元素上的其他元素永遠也不會成爲最小元素,只有遇到比當前最小元素更小(或相等)的元素時,才更新最小數據棧,換句話說,在正常數據棧每彈出一個元素的過程中,min函數得到的最小元素一定是非遞減的,也就是說最小棧的入棧數據序列一定是非遞增的,以此得到了最小棧維護數據的特性。就可以建立該棧了


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