棧、佇列

weixin_33843409發表於2018-03-05

預備知識:

棧:   取出棧頂元素:S.top();              判斷棧是否為空 :S.empty();           將元素x 新增 至棧:S.push(x)

         彈出棧頂:S.pop();                    求棧儲存元素的 個數 :S.size()

佇列:判斷佇列是否為空 :Q.empty();  返回佇列頭部元素:Q.front();          返回佇列尾部元素:Q.back()          彈出 佇列頭部元素:Q.pop();     將元素x 新增 至佇列:Q.push(x);     求佇列儲存元素的個數 :Q.size()

LeetCode 255

一開始想把佇列改寫了,發現queue的原始碼是改了deque做的,deque的基礎結構我懂,但是以我現在的技術來看,改起來還有點困難,所以就想到用兩個佇列來實現棧的功能。

以後有機會再寫一個改了deque實現棧功能的版本吧,先打個碼。

/*Implement the following operations of a stack using queues.

push(x) – Push element x onto stack.
pop() – Removes the element on top of the stack.
top() – Get the top element.
empty() – Return whether the stack is empty.

Notes:
You must use only standard operations of a queue 
– which means only push to back, peek/pop from front, size, and is empty operations are valid.
Depending on your language, queue may not be supported natively. 
You may simulate a queue by using a list or deque (double-ended queue), 
as long as you use only standard operations of a queue.
You may assume that all operations are valid (有效的)
(for example, no pop or top operations will be called on an empty stack).

佇列的一些基本操作
push(x) 將x壓入佇列的末端
pop() 彈出佇列的第一個元素(隊頂元素),注意此函式並不返回任何值
front() 返回第一個元素(隊頂元素)
back() 返回最後被壓入的元素(隊尾元素)
empty() 當佇列為空時,返回true
size() 返回佇列的長度
*/ 

#include "stdafx.h"
#include <iostream>
#include<queue>
using namespace std;

//建立兩個佇列物件(之前沒寫using namespace std,就一直說deque是未宣告的識別符號)
//一個用於儲存當前資訊,如果呼叫pop函式,則會用上另一個佇列
queue<int>stack_model_one;
queue<int>stack_model_two;

//push(x) – Push element x onto stack.
void push(int m) {
	//找到當前棧
	//如果兩個佇列都為空,則存入第一個佇列,此時應該是首次push
	if (stack_model_one.empty()&& stack_model_two.empty()) {
		stack_model_one.push(m);
		cout << "入棧成功" << endl;
	}
	//第一個佇列為空,第二個佇列不為空,此時當前棧是第二個佇列
	else if (stack_model_one.empty() && !stack_model_two.empty()) {
		stack_model_two.push(m);
		cout << "入棧成功" << endl;
	}
	//第二個佇列為空,第一個佇列不為空,此時當前棧是第一個佇列
	else if (stack_model_two.empty()&&!stack_model_one.empty()) {
		stack_model_one.push(m);
		cout << "入棧成功" << endl;
	}
	else {
		cout << "入棧失敗" << endl;
	}
}

//pop() – Removes the element on top of the stack.
void pop( int length) {
	int p = 0;
	if (stack_model_one.empty() && stack_model_two.empty()) {		
		cout << "出棧失敗" << endl;
	}
	//第一個佇列為空,第二個佇列不為空,此時當前棧是第二個佇列
	else if (stack_model_one.empty() && !stack_model_two.empty()) {
		//將第二佇列前length的元素賦值給佇列一,然後將佇列二制空
		for (int i = 0; i < length;i++) {
			stack_model_one.push(stack_model_two.front());
			stack_model_two.pop();
		}
		//刪除佇列二的最後一個元素
		stack_model_two.pop();
		cout << "出棧成功" << endl;
	}
	//第二個佇列為空,第一個佇列不為空,此時當前棧是第一個佇列
	else if (stack_model_two.empty() && !stack_model_one.empty()) {	
		//將第一佇列前length的元素賦值給佇列二,然後將佇列一制空
		for (int i = 0; i < length; i++) {
			stack_model_two.push(stack_model_one.front());
			stack_model_one.pop();
		}
		//刪除佇列一的最後一個元素
		stack_model_one.pop();
		cout << "出棧成功" << endl;
	}
	else {
		cout << "入棧失敗" << endl;
	}
}

//top() – Get the top element.
void top() {
	if (stack_model_one.empty() && stack_model_two.empty()) {
		cout << "無棧頂元素" << endl;
	}
	//第一個佇列為空,第二個佇列不為空,此時當前棧是第二個佇列
	else if (stack_model_one.empty() && !stack_model_two.empty()) {
		cout << "棧頂元素為:" << stack_model_two.back() << endl;
	}
	//第二個佇列為空,第一個佇列不為空,此時當前棧是第一個佇列
	else if (stack_model_two.empty() && !stack_model_one.empty()) {
		cout << "棧頂元素為:" << stack_model_one.back() << endl;
	}
	else {
		cout << "棧頂元素獲取失敗" << endl;
	}
}

//empty() – Return whether the stack is empty.
void empty() {
	//如果兩個佇列都為空,則棧為空
	if (stack_model_one.empty() && stack_model_two.empty()) {
		cout << "當前為空棧" << endl;
	}
	else if (stack_model_one.empty() && !stack_model_two.empty()) {
		cout << "當前棧不為空" << endl;
	}
	else if (stack_model_two.empty() && !stack_model_one.empty()) {
		cout << "當前棧不為空" << endl;
	}
	else {
		cout << "棧是否為空判斷失敗" << endl;
	}
}

int main()
{
	
	cout << "push操作請輸入“1”" << endl;
	cout << "pop操作請輸入“2”" << endl;
	cout << "top操作請輸入“3”" << endl;
	cout << "empty操作請輸入“4”" << endl;

	//用於記錄輸入的操作序號
	int n = 0;
	//用於記錄輸入的值
	int m=0;
	//用於記錄佇列的長度
	int length = 0;
	while (1) {
		cin >> n;
		//輸入你要執行的操作
		switch (n) {
		case 1:
			cout << "輸入要插入的值" << endl;
			cin >> m;
			push( m);
			length++;
			break;
		case 2:
			//傳入length-1,直接保留length長度的資訊就好
			pop( length-1);
			length--;
			break;
		case 3:
			top ();
			break;
		case 4:
			empty();
			break;
		default:
			break;
		}
	}
    return 0;
}


老師講解的方法:

使用佇列實現棧——當push元素時,先將儲存資料的佇列中的元素存入臨時佇列,push之後再把臨時佇列中的元素push到儲存資料的佇列中。



使用棧實現佇列——當push元素時,先將儲存資料的棧中的元素存入臨時棧中,push之後再把臨時棧中的元素push到儲存資料的棧中。



老師講解的方法:

雙棧法,即用兩個棧 ,來實現佇列的功能。一個棧為輸入棧input_stack,一個棧為輸出棧output_stack。

push操作時,將元素壓入input_stack。pop操作時,當output_stack不為空時,直接彈出棧頂元素,為空,則將input_stack的元素全部壓入output_stack中。  如此,時間複雜度只有O(1)

下面是自己實現的雙棧法。

#include "stdafx.h"
#include<iostream>
#include<stack>
using namespace std;

//入隊(無意中get了傳遞容器的技能,打個碼MARK!!!!!!!!!!!!!!!!!!!)
void push(stack<int >&input_stack, int m) {
	input_stack.push(m);
	cout << "入隊成功" << endl;
}

//出隊
void pop(stack<int >&input_stack, stack<int >&output_stack) {
	//當output_stack為空
	if (output_stack.empty()) {
		//將input_stack元素全部壓入output_stack
		while (!input_stack.empty()) {
			output_stack.push(input_stack.top());
			input_stack.pop();			
		}
		output_stack.pop();
		cout << "出隊成功" << endl;
	}
	//當output_stack不為空
	else {
		output_stack.pop();
		cout << "出隊成功" << endl;
	}
}
int main()
{
	stack<int>input_stack;
	stack<int>output_stack;
	char k='i';
	int n = 0, m = 0;

	cout<<"push操作請輸入“1”"<<endl;
	cout << "pop操作請輸入“2”" << endl;
	
	while (1) {		
		cin >> n;
		switch (n) {
		case 1:
			cout << "請輸入要加入的元素" << endl;
			cin >> m;
			push(input_stack, m);
			break;
		case 2:
			pop(input_stack, output_stack);
			break;
		default:break;
		}		
	}
    return 0;
}



LeetCode 155


Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

push(x) -- Push element x onto stack.
pop() -- Removes the element on top of the stack.
top() -- Get the top element.
getMin() -- Retrieve the minimum element in the stack.
Example:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> Returns -3.
minStack.pop();
minStack.top();      --> Returns 0.
minStack.getMin();   --> Returns -2.

model.h檔案:改寫了queue,寫了一個實現要求功能的檔案。時間複雜度是O(n),這個方法不是特別好。

#pragma once
#ifndef _STACK_
#define _STACK_
#include<iostream>
#include<queue>
using namespace std;

template<class T,class Sequence=queue<T>>
class Stack {
protected:
	Sequence c;
	Sequence d;
private:	
	int m;
public:
	//push(x) --Push element x onto stack.
	void push(int m) {		
		if (c.empty() && d.empty()) {
			c.push(m);
			cout << "入棧成功" << endl;
		}
		else if (!c.empty() && d.empty()) {
			c.push(m);
			cout << "入棧成功" << endl;
		}
		else if (c.empty() && !d.empty()) {
			d.push(m);
			cout << "入棧成功" << endl;
		}
		else {
			cout << "入棧失敗,特殊原因" << endl;
		}		
	}
	//pop() --Removes the element on top of the stack.
	void pop() {
		if (c.empty() && d.empty()) {			
			cout << "出棧失敗" << endl;
		}
		else if (!c.empty() && d.empty()) {
			c.pop();
			cout << "出棧成功" << endl;
		}
		else if (c.empty() && !d.empty()) {
			d.pop();
			cout << "出棧成功" << endl;
		}
		else {
			cout << "出棧失敗,特殊原因" << endl;
		}
	}
	//top() --Get the top element.
	void top() {
		if (c.empty() && d.empty()) {
			cout << "獲取棧頂元素失敗" << endl;
		}
		else if (!c.empty() && d.empty()) {
			while (c.size() > 1) {
				d.push(c.front());
				c.pop();
			}
			//獲取棧頂元素
			m=c.front();
			d.push(c.front());
			//排空c中的元素
			c.pop();
			cout << "棧頂元素為:" <<m<< endl;
		}
		else if (c.empty() && !d.empty()) {
			while (d.size() > 1) {
				c.push(d.front());
				d.pop();
			}
			//獲取棧頂元素
			m = d.front();
			c.push(d.front());
			//排空c中的元素
			d.pop();
			cout << "棧頂元素為:" << m << endl;
		}
		else {
			cout << "獲取棧頂元素失敗,特殊原因" << endl;
		}
	}
	//getMin() --Retrieve the minimum element in the stack.
	void getMin() {
		if (c.empty() && d.empty()) {
			cout << "無最小元素" << endl;
		}
		else if (!c.empty() && d.empty()) {
			m = c.front();
			d.push(c.front());
			c.pop();
			while (c.size() > 0) {
				if (m > c.front()) {
					m = c.front();
				}
				d.push(c.front());
				c.pop();
			}
			cout << "最小元素是:" <<m<< endl;
		}
		else if (c.empty() && !d.empty()) {
			m = d.front();
			c.push(d.front());
			d.pop();
			while (d.size() > 0) {
				if (m > d.front()) {
					m = d.front();
				}
				c.push(d.front());
				d.pop();
			}
			cout << "最小元素是:" << m << endl;
		}
		else {
			cout << "獲取最小元素失敗,特殊原因" << endl;
		}
	}
};
#endif


.cpp檔案,呼叫函式

#include "stdafx.h"
#include<iostream>
#include"model.h"
using namespace std;

int main()
{
	Stack<int> stack_model;
	int n=0,m = 0;
	cout << "push操作請輸入“1”" << endl;
	cout << "pop操作請輸入“2”" << endl;
	cout << "top操作請輸入“3”" << endl;
	cout << "getMin操作請輸入“4”" << endl;
	while (1) {
		cin >> n;
		switch (n) {
		case 1:
			cout<<"請輸入要入棧的值"<<endl;
			cin >> m;
			stack_model.push(m);
			break;
		case 2:
			stack_model.pop();
			break;
		case 3:
			stack_model.top();
			break;
		case 4:
			stack_model.getMin();
			break;
		}
	}
    return 0;
}


老師講解的方法: 時間複雜度是O(1)

設定兩個棧, 資料棧data_stack 與 最小值棧min_stack ,這兩個棧對於新增元素push與彈出棧
頂元素pop都是 同步進行 的:
1.push(x) : 將元素x直接壓入資料棧data_stack中,若x小於最小值棧棧頂,則將 x 壓入 最小值棧中,否則將 最小值棧棧頂壓入最小值棧。
2.pop() :  同時彈出( 移除) 資料棧棧頂與最小值棧頂元素。
3.top() : 返回 資料棧data_stack 棧頂元素。
4.getMin() : 返回 最小值棧min_stack 棧頂元素。




POJ 1363

/*
題目大意:

已知火車要從A入站,然後從C出站。火車進站的順序為1~N,現在給你出站的順序。
問:能不能通過站臺改變火車出站順序來實現按所給順序出站。

解題思路:

把站臺看做是一個棧,按1~N的順序遍歷火車原先順序,先入棧,
如果棧頂的火車編號和所給出站順序將要出站的編號一樣。
那麼火車就出棧,直到棧裡邊所有滿足出站順序的火車都出站,否則就一直入棧。
最後判斷所有火車是否都出站了。若都出站,輸出Yes,否則輸出No。
*/ 

#include"stdafx.h"
#include<iostream>
#include<stack>
using namespace std;

int main()
{
	cout << "請輸入要輸入的元素個數" << endl;
	int m = 0, temp = 0;

	while (cin >> m) {
		//建立一個陣列,用於儲存輸入的數字串
		int *array;
		array = (int *)malloc(sizeof(int)*m);
		stack<int>stack_model;

		cout << "請輸入需要判斷的數字串" << endl;
		//將輸入的數字串存入陣列
		for (int i = 0; i < m; i++) {
			cin >> temp;
			array[i] = temp;
		}

		//對比元素,值在1~m之間
		int flag = 1;
		for (int i = 0; i < m; i++) {
			//當前值小於等於輸入的數字串中需要對比的值時,入棧
			while (flag <= array[i]) {
				stack_model.push(flag);
				flag++;
			}
			//此時棧頂元素等於array[i]
			int cur = stack_model.top();
			//如果輸入的數字串符合棧,則一共會彈出m次
			stack_model.pop();
			if (cur != array[i]) {
				cout<<"數字串不是棧順序"<<endl;
				break;
			}
		}
		if (stack_model.size() == 0) {
			cout<<"數字串是棧順序"<<endl;
		}
	}
	return 0;
}

上面自己寫的演算法的時間複雜度太大,需要修改。


老師講解的方法:

同時使用一個佇列與一個棧來解決該問題

設佇列order與棧為S。佇列order儲存待判斷是否合法的出棧序列 ,使用棧S用來模擬出棧與入棧的過程。

按照1-n的順序,將元素 push 進入棧S 中:每push一個元素,即檢查棧頂 S.top()是否與佇列頭部元素order.front()相同。

如果相同則同時彈出棧頂元素與佇列頭部元素, 直到棧空或棧頂與佇列頭部元素不同 。

若最終棧為空 ,則說明序列合法 ,否則不合法。


預備知識:堆

我們一般使用二叉堆來實現優先順序佇列 ,它的內部調整演算法複雜度為log(N), 標準STL 的優先順序佇列包括如下5 種操作,設堆H:

1.取出堆頂元素:H.top();           2.判斷堆是否為空 :H.empty();           3.將元素x新增 至堆:H.push(x)

4. 彈出堆頂:H.pop();                5.求堆儲存元素的個數 :H.size()


優先佇列根據權值,將入隊元素進行排序。只允許一端入隊另一端出隊。底層容器是vector。


LeetCode 215


思路:快排的時間複雜度是nlogn。感覺這題不是中等難度的題,是easy題。

class Solution {
public:
    int findKthLargest(vector<int>& nums, int k) {
        sort(nums.begin(),nums.end());
        int temp=0;
        temp=nums.size()-k;
        return nums[temp];
    }
};


方法二,優先佇列




LeetCode 295


方法:動態維護一個 最大堆 與一個 最小堆 ,最大堆儲存一半資料,最小堆儲存

一半資料, 維持 最大堆的堆頂比最小堆的堆頂小,即可解決該問題。


相關文章