用实例讲解栈和队列(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、两个栈实现队列
class TwoStack {
public :
     stack< int > pushStack,popStack;
     vector< int > twoStack(vector< int > ope,  int n) {
         vector< int > q;
         for ( int i =  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();              
             }
         }
         return q;
     }
};

3、实现栈的逆序
解法:在限定 只能用递归和栈本身,而不能再申请别的数据结构的情况下。主要有两个递归过程。
①、getBase递归地获取栈底数据,并将栈底数据从栈中移除,栈中其他数据不变。
②、reverse递归地将每一次获得的栈底数据重新入栈,从而实现逆序。
class StackReverse {
public :
     int getBase(stack< int > &s) {
         int base,top = s.top();
             s.pop();
         if (!s.empty()) {
             base = getBase(s);
             s.push(top);
        
         else
             return top;
         return base;
         
     }
 
     void reverse(stack< int > &s) {
         int base = getBase(s);
         if (!s.empty())
             reverse(s);
         s.push(base);
         return ;
     }
 
     vector< int > reverseStack(vector< int > A,  int n) {
         if (A.empty() || n ==  1 )
             return A;
         stack< int > s;
         vector< int > reverseA;
         for ( int i = n- 1 ;i >=  0 ;i--)
             s.push(A[i]);
         reverse(s);
         do {
             reverseA.push_back(s.top());
             s.pop();
         } while (!s.empty());
         
         return reverseA;
     }
};
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;
    }
};

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值