用實例講解棧和隊列(C++)

一、棧和隊列
1、實現一個新型的棧結構,具有pop、push、top、size和getMin操作。
解法:用兩個普通棧實現。
class Solution {
public:
    stack<int> data,minData;
    void push(int value) {
        data.push(value);
        if (minData.empty())
            minData.push(value);
        if (value < minData.top())            
            minData.push(value);           
        else
            minData.push(minData.top());
    }
    void pop() {
        data.pop();
        minData.pop();
    }
    int top() {
        return data.top();
    }
    int min() {
        return minData.top();
    }
};

2、兩個棧實現隊列
classTwoStack {
public:
    stack<int> pushStack,popStack;
    vector<int> twoStack(vector<int> ope, intn) {
        vector<int> q;
        for(inti = 0;i < n;i++) {
            if(ope[i] > 0) {
                while(!popStack.empty()) {
                    pushStack.push(popStack.top());
                    popStack.pop();
                }               
                pushStack.push(ope[i]);                   
            }
            if(ope[i] == 0) {
                while(!pushStack.empty()) {
                    popStack.push(pushStack.top());
                    pushStack.pop();
                }
                q.push_back(popStack.top());
                popStack.pop();              
            }
        }
        returnq;
    }
};

3、實現棧的逆序
解法:在限定只能用遞歸和棧本身,而不能再申請別的數據結構的情況下。主要有兩個遞歸過程。
①、getBase遞歸地獲取棧底數據,並將棧底數據從棧中移除,棧中其他數據不變。
②、reverse遞歸地將每一次獲得的棧底數據重新入棧,從而實現逆序。
classStackReverse {
public:
    intgetBase(stack<int> &s) {
        intbase,top = s.top();
            s.pop();
        if(!s.empty()) {
            base = getBase(s);
            s.push(top);
        
        else
            returntop;
        returnbase;
         
    }
 
    voidreverse(stack<int> &s) {
        intbase = getBase(s);
        if(!s.empty())
            reverse(s);
        s.push(base);
        return;
    }
 
    vector<int> reverseStack(vector<int> A, intn) {
        if(A.empty() || n == 1)
            returnA;
        stack<int> s;
        vector<int> reverseA;
        for(inti = n-1;i >= 0;i--)
            s.push(A[i]);
        reverse(s);
        do{
            reverseA.push_back(s.top());
            s.pop();
        }while(!s.empty());
         
        returnreverseA;
    }
};
4、雙棧排序
解法:在最多隻能再申請一個棧的情況下實現對棧內數據的排序。類似於插入排序,sort棧中存放已排好序的序列,將init棧的棧頂元素壓入sort棧時要判斷應該壓入的位置,所以每次都得將init棧頂元素一一地與sort棧的棧頂元素比較,以找到其應該插入的位置。
class TwoStacks {
public:

    void stackSort(vector<int> &init,vector<int> &sort) {
        int temp;       
        sort.push_back(init.back());
        init.pop_back();
        while (!init.empty()) {
            temp = init.back();
            init.pop_back();
            if (temp <= sort.back()) {
                sort.push_back(temp);
            }
            else {
                do {
                    init.push_back(sort.back());
                    sort.pop_back();
                }while (!sort.empty() && temp > sort.back());
                sort.push_back(temp);
            }           
        }
        return;
    }

    vector<int> twoStacksSort(vector<int> numbers) {
        int n = numbers.size();
        if (n < 2)
            return numbers;
        vector<int> sortNumbers;
        stackSort(numbers,sortNumbers);        
        return sortNumbers;        
    }
};

5、滑動窗口問題
問題描述:有一個整型數組 arr 和一個大小爲 w 的窗口從數組的最左邊滑到最右邊,窗口每次向右邊滑一個位置。 返回一個長度爲n-w+1的數組res,res[i]表示每一種窗口狀態下的最大值。
最優解法:用雙端隊列實現。隊頭保存遍歷過的元素中最大元素的下標。
①每遍歷一個新元素就將該元素和隊尾對應的元素比較,小於則將其下標從隊尾入隊,大於則將隊尾元素出隊,繼續與新的隊尾對應元素比較,直到遇到比該元素大的隊尾對應元素或者直到隊空,然後將該元素下標從隊尾入隊。
②找到當前元素下標正確的入隊位置併入隊後,再判斷當前隊頭元素是否處在當前窗口的範圍內,是則記錄隊頭對應元素,否則將隊頭出隊,記錄新的隊頭對應元素。

class SlideWindow {
public
:    
    vector<int> slide(vector<int> arr, int n, int w) {
        deque<int> index;
           vector<int> winMax;
        for (int i = 0;i < n;i++) {
            if (!index.empty()) {
                if (arr[i] >= arr[index.back()]) {
                    do {
                    index.pop_back();
                }while (!index.empty() && arr[i] >= arr[index.back()]);               
            }      
        }

        index.push_back(i);

        if (index.back() >= w-1) {
            if (index.back() - index.front() >= w) {
                index.pop_front();
            }
            winMax.push_back(arr[index.front()]);
        }
      }
    return winMax;
    }
};

6、對於一個沒有重複元素的整數數組,請用其中元素構造一棵MaxTree。
問題描述:MaxTree定義爲一棵二叉樹,其中的節點與數組元素一一對應,同時對於MaxTree的每棵子樹,它的根的元素值爲子樹的最大值。
解法:對於數組中的每個元素,其在樹中的父親爲數組中它左邊比它大的第一個數和右邊比它大的第一個數中更小的一個。問題的關鍵在於求出每個元素對應的左邊最大值和右邊最大值。用棧可以實現。

class MaxTree {
public:

    vector<int> findMax(vector<int> &A,int n,char dir) {
        stack<int> fMax;
        vector<int> max;

        int k = (dir == 'l')?0:n-1;

        for (;k < n && k >=0;) {
            if (!fMax.empty()) {
                if (A[k] >= A[fMax.top()]) {
                    do {
                        fMax.pop();
                    }while (!fMax.empty() && A[k] >= A[fMax.top()]);
                }               
            }

       max.push_back(fMax.empty()?-1:fMax.top());           
       fMax.push(k);
       k = (dir == 'l')?k+1:k-1;       
     }
        return max;
    }

    vector<int> buildMaxTree(vector<int> A, int n) {
        vector<int> father;
        if (n < 1)
            return father;

        vector<int> left = findMax(A,n,'l');        
        vector<int> right = findMax(A,n,'r');

        for (int i = 0;i < n;i++) {
            int j = n-i-1;
            if (left[i] == -1 && right[j] == -1)
                father.push_back(-1);
            else if (left[i] != -1 && right[j] != -1)
                father.push_back(A[left[i]] < A[right[j]]?left[i]:right[j]);
            else
 
                father.push_back(left[i] != -1?left[i]:right[j]);
        }
        return father;
    }
};

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