栈结构的经典算法题
棧結構
?
顛倒一個棧的元素順序
問題:假設有一個棧{1,2,3,4,5,6},6是棧頂,1是棧底,現在要把這個棧中的元素顛倒一下。
思路:最簡單的辦法當然是把棧中的元素依次pop到一個數組中,然后把這個數組再push回棧里面即可,但這樣需要O(n)的輔助空間。
下面介紹一種僅使用O(1)輔助空間的算法,我們知道,可以使用遞歸來模擬棧的操作。我們借助函數遞歸pop元素,這樣在遞歸的函數棧上依次有
{6,5,4,3,2,1},1是棧頂,6是棧底,然后在遞歸返回的時候,如何把當前元素塞到原棧的底部呢?這里借助了另一個遞歸!
?
C++代碼實現如下:
void Add2Bottom(stack<int> &s, int val) {int top;if (s.empty()) {s.push(val);} else {top = s.top();s.pop(); Add2Bottom(s, val);s.push(top);} }void Reverse(stack<int> &s) {int top;if (!s.empty()) {top = s.top();s.pop();Reverse(s);Add2Bottom(s, top);} }int main() {int n;int array[6] = {1,2,3,4,5,6};stack<int> s;for (n=0; n<6; n++) s.push(array[n]);Reverse(s);while (!s.empty()) {cout<<s.top()<<endl;s.pop();} }?
棧的min函數
定義棧的數據結構,要求添加一個min函數,能夠得到棧的最小元素。要求函數min、push以及pop的時間復雜度都是O(1)。
思路:利用輔助棧,每次對stack push/pop一個元素時,同時也要更新輔助棧(存儲最小元素的位置),例如:
?步驟????????????? 數據棧??????????? 輔助棧??????????????? 最小值
1.push 3??? 3????????? 0???????????? 3
2.push 4??? 3,4??????? 0,0?????????? 3
3.push 2??? 3,4,2????? 0,0,2???????? 2
4.push 1??? 3,4,2,1??? 0,0,2,3?????? 1
5.pop?????? 3,4,2????? 0,0,2???????? 2
6.pop?????? 3,4??????? 0,0?????????? 3
7.push 0??? 3,4,0????? 0,0,2???????? 0
?
C++代碼實現:
#include <deque> #include <assert.h> #include <iostream>using namespace std;template <typename T> class CStackWithMin {public:CStackWithMin(void) {}virtual ~CStackWithMin(void) {}T& top(void);const T& top(void) const;void push(const T& value);void pop(void);const T& min(void) const;private:deque<T> m_data; // the elements of stackdeque<size_t> m_minIndex; // the indices of minimum elements };// get the last element of mutable stack template <typename T> T& CStackWithMin<T>::top() {return m_data.back(); }// get the last element of non-mutable stack template <typename T> const T& CStackWithMin<T>::top() const {return m_data.back(); }// insert an elment at the end of stack template <typename T> void CStackWithMin<T>::push(const T& value) {// append the data into the end of m_data m_data.push_back(value);// set the index of minimum elment in m_data at the end of m_minIndexif(m_minIndex.size() == 0) {m_minIndex.push_back(0);} else {if(value < m_data[m_minIndex.back()])m_minIndex.push_back(m_data.size() - 1);elsem_minIndex.push_back(m_minIndex.back());} }// erease the element at the end of stack template <typename T> void CStackWithMin<T>::pop() {// pop m_data m_data.pop_back();// pop m_minIndex m_minIndex.pop_back(); }// get the minimum element of stack template <typename T> const T& CStackWithMin<T>::min() const {assert(m_data.size() > 0);assert(m_minIndex.size() > 0);return m_data[m_minIndex.back()]; }int main()
{
class CStackWithMin<int> stk;
stk.push(3);
cout<<"min="<<stk.min()<<endl;
stk.push(4);
cout<<"min="<<stk.min()<<endl;
stk.push(2);
cout<<"min="<<stk.min()<<endl;
stk.push(1);
cout<<"min="<<stk.min()<<endl;
stk.pop();
cout<<"min="<<stk.min()<<endl;
stk.pop();
cout<<"min="<<stk.min()<<endl;
stk.push(0);
cout<<"min="<<stk.min()<<endl;
}
?
?
?
棧的push、pop序列
輸入兩個整數序列,其中一個序列表示棧的push順序,判斷另一個序列有沒有可能是對應的pop順序。為了簡單起見,我們假設push序列的任意兩個整數都是不相等的。?
比如輸入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是一個pop系列。因為可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,這樣得到的pop序列就是4、5、3、2、1。但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。
?
?C++實現:
int verify(int in[], int out[], int N) {int n; int m = 0;stack<int> s;for (n=0; n<N; n++) {s.push(in[n]); while (!s.empty()) {if (s.top() == out[m]) {s.pop(); m++;} else {break; } } } return s.empty(); }int main() {int ret;int in[5] = {1,2,3,4,5};int out[5] = {4,3,5,1,2};ret = verify(in, out, 5); cout<<"ret="<< ret<<endl; }?
?
?
用棧實現隊列
設2 個棧為A和B,A用作入隊,B用作出隊。
隊滿:A滿且B不為空;
隊空:A和B都為空;
入隊:
(1) 如果A未滿,將新元素push 入棧A;
(2) 如果A已滿,將棧A中所有元素依次pop 出并push 到棧B,然后將元素入棧A;
出隊:
(1) 如果B為空,則將棧A 中所有元素依次pop 出并push 到棧B,然后將元素出棧B;
(2) 如果B不為空,將棧B 的棧頂元素pop 出;
?
C++代碼實現:
bool queue_empty(stack<int> &s1, stack<int> &s2) {return s1.empty() && s2.empty(); }void enqueue(stack<int> &s1, stack<int> &s2, int val) {s1.push(val); }void dequeue(stack<int> &s1, stack<int> &s2, int &val) {int top;if (s2.empty()) {while (!s1.empty()) {top = s1.top(); s1.pop();s2.push(top);} } if (!s2.empty()) {val = s2.top();s2.pop();} else {cout<<"error: queue is empty"<<endl;} }int main() {int n;int array[6] = {1,2,3,4,5,6};stack<int> s1; stack<int> s2; for (n=0; n<6; n++) enqueue(s1, s2, array[n]);while (!queue_empty(s1, s2)) {dequeue(s1, s2, n);cout<<n<<endl;}}注意:這里沒有考慮棧空間可能滿的問題。
?
其實,也可以用一個棧來模擬隊列結構,仍然是借助遞歸棧,每次往棧插入元素時,把它塞到棧底,這樣就實現了FIFO的隊列結構。
代碼如下:
void enqueue2(stack<int> &s, int val) {int top;if (s.empty()) {s.push(val);} else {top = s.top();s.pop();enqueue2(s, val);s.push(top); } }int main() {int n;int array[6] = {1,2,3,4,5,6};stack<int> s;for (n=0; n<6; n++) enqueue2(s, array[n]); while (!s.empty()) {n = s.top();s.pop();cout<<n<<endl;} }?
?
用隊列實現棧
?
設2 個隊列為A和B,A用作入隊/出隊,B用作輔助。
隊滿:A滿且B不為空;
隊空:A和B都為空;
入棧:將新元素插入隊列A;
出棧:
(1) 除最后一個元素外,將隊列A的元素全部插入到隊列B;
(2) 將隊列A的最后一個元素出隊;
(3) 將隊列B的元素換回到隊列A;
?
void stack_pop(queue<int> &q1, queue<int> &q2, int &n) {int i, head;while (!q1.empty()) {head = q1.front();q1.pop();if (q1.empty()) {n = head;} else {q2.push(head);}}while (!q2.empty()) {head = q2.front();q1.push(head);q2.pop();} }int main() {int n;int array[6] = {1,2,3,4,5,6};queue<int> q1, q2;for (n=0; n<6; n++) q1.push(array[n]);while (!q1.empty()) {stack_pop(q1, q2, n);cout<<n<<endl;} }?
轉載于:https://www.cnblogs.com/chenny7/p/4126910.html
總結
- 上一篇: 隐藏input边框(ie6、ie7)
- 下一篇: Android中常用的编码和解码(加密和