1. 程式人生 > >佇列與棧面試題C++

佇列與棧面試題C++

概念

1.圖的深度優先遍歷(DFS)
可以用棧實現,從根結點開始沿左孩子到最深的節點壓入棧中,然後依次彈出,若棧頂節點還有沒有訪問的孩子,則沒訪問過得孩子入棧直到最深的節點,然後再彈出。元素入棧順序則為深度優先遍歷順序。
2.圖的寬度優先遍歷(BFS)
可以用佇列實現,將根結點放入佇列,每彈出一個節點,就將該節點的孩子全部放入佇列,放入佇列的順序為寬度優先遍歷順序。

示例一

實現一個特殊的棧,在實現棧的基礎功能的基礎上,再實現返回棧中最小元素的操作getMin。
要求:1.pop,push,getMin操作的時間複雜度都為 O

( 1 ) O(1)
2.設計的棧型別可以使用現成的棧結構。
分析:
思路一:構造兩個棧,一個stackData儲存資料,一個stackMin儲存當前的最小值,只有當前數小於等於stackMin的棧頂元素時,該數放入stackMin中,否則不壓入,當彈出時,若stackData棧頂等於stackMin時,stackMin才彈出,否則不彈出。

template <typename T> class newStack {
public:
	std::stack<T> stackData;
	std::stack<T> stackMin;
	void push(T data) {
		stackData.push(data);
		if (stackMin.empty())
		{
			stackMin.push(data);
		}
		else
		{
			if (data <= stackMin.top()) {
				stackMin.push(data);
			}
		}
	}
	void pop() {
		if (!stackData.empty()) {
			if (stackData.top() == stackMin.top()) {
				stackMin.pop();
			}
			stackData.pop();
		}
	}
	T top();
	T getMin();
	bool empty();

};
template <typename T> T newStack<T>::top() {
	return stackData.top();
}
template <typename T> T newStack<T>::getMin() {
	return stackMin.top();
}
template <typename T> bool newStack<T>::empty() {
	return stackData.empty();
}

思路二:構造兩個棧,一個stackData儲存資料,一個stackMin儲存當前的最小值,每次壓入資料時兩個棧都壓入,stackData壓入給定資料,stackMin壓入給定資料或stackMin棧頂元素較小的那個,彈出時兩個棧一起彈出。

template <typename T> class newStack {
public:
	std::stack<T> stackData;
	std::stack<T> stackMin;
	void push(T data);
	void pop();
	T top();
	T getMin();
	bool empty();
};

template <typename T> void newStack<T>::push(T data) {
	stackData.push(data);
	if (stackMin.empty()) {
		stackMin.push(data);
	}
	else {
		if (stackMin.top() >= data) {
			stackMin.push(data);
		}
		else{
			stackMin.push(stackMin.top());
		}
	}
}
template <typename T> void newStack<T>::pop() {
	if (!stackData.empty()) {
		stackData.pop();
		stackMin.pop();
	}
}
template <typename T> T newStack<T>::top() {
	return stackData.top();
}
template<typename T> T newStack<T>::getMin() {
	return stackMin.top();
}
template<typename T> bool newStack<T>::empty() {
	return stackData.empty();
}

示例二

編寫一個類,只能用兩個棧結構實現佇列,支援佇列的基本操作(add,poll,peek)。
分析:一個棧stackPush用來放入,一個棧stackPop用來彈出。放資料的時候直接放到stackPush中,彈出時,若stackPop不為空,直接彈出,若為空且stackPush不為空,則將stackPush資料依次彈出壓入stackPop後再從stackPop中彈出。

#include<iostream>
#include<stack>
#include<thread>
using std::cout;
using std::endl;

template <typename T> class newQueue {
private:
	std::stack<T> stackPush;
	std::stack<T> stackPop;
public:
	void add(T data) {
		stackPush.push(data);
	}
	void poll() {
		if (!stackPop.empty()) {
			stackPop.pop();
		}
		else{
			if (!stackPush.empty()) {
				while (!stackPush.empty()){
					stackPop.push(stackPush.top());
					stackPush.pop();
				}
			}
		}
	}
	T peek() {
		if (!stackPop.empty()) {
			return stackPop.top();
		}
		else {
			if (!stackPush.empty()) {
				while (!stackPush.empty()) {
					stackPop.push(stackPush.top());
					stackPush.pop();
				}
				return stackPop.top();
			}
			else {
				throw;
			}
		}
	}
	bool empty() {
		return stackPop.empty() && stackPush.empty();
	}
};


int main(void) {
	newQueue<int> queueK;
	queueK.add(1);
	queueK.add(2);
	queueK.add(3);

	while (!queueK.empty()){
		cout << queueK.peek() << endl;
		queueK.poll();
	}
	
	while (true)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
}

示例三

實現一個棧的逆序,但是隻能用遞迴函式和這個棧本身的操作來實現,而不能自己申請另外的資料結構。
分析:構造兩個函式
1.移除棧底元素並返回
2.迴歸取空棧並放入當前取出的棧底

#include<iostream>
#include<stack>
#include<thread>
using std::cout;
using std::endl;

template<typename T> T getBottom(std::stack<T> &stackR) {
	if (stackR.empty()) {
		return NULL;
	}
	T nowData = stackR.top();
	stackR.pop();
	if (stackR.empty()) {
		return nowData;
	}
	T lastData = getBottom(stackR);
	stackR.push(nowData);
	return lastData;
}


template<typename T> void reverseStack(std::stack<T> &stackR) {
	if (stackR.empty()) {
		return;
	}
	T nowData = getBottom(stackR);
	reverseStack(stackR);
	stackR.push(nowData);
}

int main(void) {
	std::stack<int> st;
	st.push(1);
	st.push(2);
	st.push(3);
	st.push(4);

	reverseStack(st);

	while (!st.empty()){
		cout << st.top() << endl;
		st.pop();
	}
	
	while (true)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
}

示例四

一個棧中元素型別為整形,現在將該棧從頂到底按從大到小排序,只許申請一個棧,除此之外可以申請新的變數,但不能申請額外的資料結構。如何完成排序。
分析:臨時申請一個棧helpStack,當Stack中的棧頂current小於等於helpStack棧頂時,將current從Stack中彈壓入helpStack,若大於,則將helpStack棧中元素彈出壓入Stack中,直到current 小於等於helpStack棧頂元素為止。重複上述過程直到Stack中元素全部壓入helpStack中。

#include<iostream>
#include<stack>
#include<thread>
using std::cout;
using std::endl;

template<typename T> void sortStack(std::stack<T> &unsortStack) {
	auto size = unsortStack.size();
	if (size < 2) {
		return;
	}
	std::stack<T> helpStack;
	T current = unsortStack.top();
	unsortStack.pop();
	while(helpStack.size() != size) {
		if (helpStack.empty()) {
			helpStack.push(current);
			current = unsortStack.top();
			unsortStack.pop();
		}
		if (current <= helpStack.top()) {
			helpStack.push(current);
			if (unsortStack.empty()) {
				break;
			}
			current = unsortStack.top();
			unsortStack.pop();
		}
		else {
			unsortStack.push(helpStack.top());
			helpStack.pop();
		}
	}

	while (!helpStack.empty()){
		unsortStack.push(helpStack.top());
		helpStack.pop();
	}
}


int main(void) {
	std::stack<int> st;
	st.push(12);
	st.push(7);
	st.push(99);
	st.push(4);
	st.push(2);
	st.push(3);
	st.push(1);

	sortStack(st);

	while (!st.empty()){
		cout << st.top() << endl;
		st.pop();
	}
	
	while (true)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
}

示例五

有一個數組arr和一個大小為w的視窗從陣列的最左端滑到最右端,視窗每次向右滑一個位置,返回一個長度為n-w+1的陣列res,res[i]表示每一種視窗狀態下的最大值。如[4, 3, 5, 4, 3, 3, 6, 7],視窗為3,res為[5,5,5,4,6,7]。
分析:時間複雜度可以做到 O ( N ) O(N) .
首先建立一個雙向佇列qmax記錄陣列的下標,若當前數為arr[i],放入規則為
1.如果qmax為空,將i放入qmax尾部。
2.如果qmax不為空,qmax隊尾下標為j,若arr[i]<arr[j],則將i放入qmax尾部。如果arr[i]>=arr[j],彈出j,重複步驟2,直到arr[i]<arr[j],將i放入qmax尾部。
如果qmax的頭j小於等於i-w,則彈出qmax隊首元素。
arr[qmax隊首]為res[i]。

#include<iostream>
#include<stack>
#include<thread>
#include<vector>
#include<queue>
using std::cout;
using std::endl;

std::vector<int> windowMax(const int *unsortArray, const int &length,const int &window) {
	std::vector<int> maxVector;
	std::deque<int> helpQueue;
	if (length < window) {
		return maxVector;
	}
	int i = 0;
	while (i<length){
		if (helpQueue.empty()) {
			helpQueue.push_back(i);
		}
		else {
			if (unsortArray[i] > unsortArray[helpQueue.back()]) {
				helpQueue.pop_back();
			}
			else {
				helpQueue.push_back(i);
				while (helpQueue.front()<=(i-window)){
					helpQueue.pop_front();
				}
				if (i >= window - 1) {
					maxVector.push_back(unsortArray[helpQueue.front()]);
				}
				++i;
			}
			
		}
	}
	return maxVector;


}

int main(void) {
	int unsortArray[8]={4, 3, 5, 4, 3, 3, 6, 7};
	std::vector<int> maxVector;
	maxVector = windowMax(unsortArray, 8, 3);
	for (auto i = maxVector.begin(); i != maxVector.end(); ++i) {
		cout << *i << endl;
	}
	
	while (true)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
	return 1;
}

示例六

給定一個沒有重複元素的陣列arr,寫出生成這個陣列的MaxTree函式,要求如果陣列長度為N,則時間複雜度為 O ( N ) O(N) ,額外空間複雜度為 O ( N ) O(N) 。MaxTree的概念如下:
1.MaxTree是一顆二叉樹,陣列的每一個值對應一個二叉樹節點。
2.包括MaxTree數在內且其中的每一顆子樹上,值最大的節點都是樹的頭。
分析:記錄兩個序列,第一個序列leftBigger記錄陣列arr中每個數左邊第一個比當前數大的數,第二個序列rightBigger記錄陣列arr中每個數右邊第一個比當前數大的數。然後比較這兩個陣列,較小的數為當前數的父節點。

#include<iostream>
#include<thread>
#include<string>
#include<queue>
#include<stack>
using std::cout;
using std::endl;
template<typename T> class BinNode {
public:	
	T data;
	int height = 0;
	BinNode<T> *parent = NULL;
	BinNode<T> *lc = NULL;
	BinNode<T> *rc = NULL;
	BinNode() = default;
	BinNode(T e, int h, BinNode<T> *pa = NULL, BinNode<T> *lcc = NULL, BinNode<T> *rcc = NULL) :
		data(e), height(h), parent(pa), lc(lcc), rc(rcc) {}
	static void tranIn(BinNode *node) {
		if (!node) {
			return;
		}
		BinNode<T>::tranIn(node->lc);
		cout << node->data << endl;
		BinNode<T>::tranIn(node->rc);
	}
};

template<typename T> std::vector<int> leftBigger(const T *unsortArray, const std::size_t length) {//尋找每個數左邊大於當前數的下標
	std::stack<T> temStack;
	std::vector<int> temVector;
	std::size_t i = 0;
	while (i < length) {
		if (temStack.empty()) {
			temVector.push_back(-1);
			temStack.push(i);
			++i;
		}
		else {
			if (unsortArray[i] > unsortArray[temStack.top()]) {
				temStack.pop();
			}
			else {
				temVector.push_back(temStack.top());
				temStack.push(i);
				++i;
			}
		}
	}
	return temVector;
}


template<typename T> std::vector<int> rightBigger(const T *unsortArray, const std::size_t length) {
	std::stack<T> temStack;
	std::vector<int> temVector;
	int i = length - 1;
	while (i >= 0) {
		if (temStack.empty()) {
			temVector.push_back(-1);
			temStack.push(i);
			--i;
		}
		else {
			if (unsortArray[i] > unsortArray[temStack.top()]) {
				temStack.pop();
			}
			else {
				temVector.push_back(temStack.top());
				temStack.push(i);
				--i;
			}
		}
	}
	return temVector;
}

template<typename T> BinNode<T>* getMaxTree(const T *unsortArray, const int length) {
	BinNode<T> *nodes = new BinNode<T>[length];
	std::vector<int> lbVector;
	std::vector<int> rbVector;
	BinNode<T> *maxNode = NULL;

	lbVector = leftBigger(unsortArray, length);
	rbVector = rightBigger(unsortArray, length);

	for (int i = 0; i < length; ++i) {
		nodes[i].data = unsortArray[i];
	}
	

	for (int i = 0; i < length; ++i) {
		if ((lbVector[i] != -1) && (rbVector[length - 1 - i] != -1)) {
			if (unsortArray[lbVector[i]] > unsortArray[rbVector[length - 1 - i]]) {
				//cout <<"choseR:" <<i << endl;
				if (nodes[rbVector[length - 1 - i]].lc == NULL) {
					nodes[rbVector[length - 1 - i]].lc = &nodes[i];
				}
				else{
					nodes[rbVector[length - 1 - i]].rc = &nodes[i];
				}
			}
			else {
				//cout << "chooseL:" << i << endl;
				if (nodes[lbVector[i]].lc == NULL) {
					nodes[lbVector[i]].lc = &nodes[i];
				}
				else {
					nodes[lbVector[i]].rc = &nodes[i];
				}
			}
		}
		else if (rbVector[length - 1 - i] != -1) {
			//cout << "r:" << i << endl;
			if (nodes[rbVector[length - 1 - i]].lc == NULL) {
				nodes[rbVector[length - 1 - i]].lc = &nodes[i];
			}
			else {
				nodes[rbVector[length - 1 - i]].rc = &nodes[i];
			}
		}
		else if (lbVector[i] != -1) {
			//cout << "l:" << i << endl;
			if (nodes[lbVector[i]].lc == NULL) {
				nodes[lbVector[i]].lc = &nodes[i];
			}
			else {
				nodes[lbVector[i]].rc = &nodes[i];
			}
		}
		else {
			//cout << "max:" << i << endl;
			maxNode = &nodes[i];
	
		}
	}
	return maxNode;
}



int main() {	
	int unsortArry[5] = { 3,4,5,1,2 };
	BinNode<int> *tree;
	tree = getMaxTree(unsortArry, 5);
	cout << "start:"<<endl;
	BinNode<int>::tranIn(tree);
	while (1)
	{
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
	}
}