当前位置:   article > 正文

算法学习-栈_mystack.push(i);

mystack.push(i);

最近计划再复习一遍数据结构,看到一篇博客:https://www.cnblogs.com/QG-whz/p/5170418.html#_label0。

1、栈(Stack)是一种线性存储结构,它具有如下特点:

(1)栈中的数据元素遵守“先进后出"(First In Last Out)的原则,简称FILO结构。(后进先出的叫法,也是可以的)

(2)限定只能在栈顶进行插入和删除操作。

2、栈的相关概念:

(1)栈顶与栈底:允许元素插入与删除的一端称为栈顶,另一端称为栈底。

(2)压栈:栈的插入操作,叫做进栈,也称压栈、入栈。

(3)弹栈:栈的删除操作,也叫做出栈。

3、栈的常用操作为:

(1)弹栈,通常命名为pop

(2)压栈,通常命名为push

(3)求栈的大小

(4)判断栈是否为空

(5)获取栈顶元素的值

4、栈的常见分类:

(1)基于数组的栈——以数组为底层数据结构时,通常以数组头为栈底,数组头到数组尾为栈顶的生长方向

(2)基于单链表的栈——以链表为底层的数据结构时,以链表头为栈顶,便于节点的插入与删除,压栈产生的新节点将一直出现在链表的头部

5、实例分析

使用标准库的栈时, 应包含相关头文件,在栈中应包含头文件: #include< stack > 。定义:stack< int > s;

  1. s.empty();         //如果栈为空则返回true, 否则返回false;
  2. s.size();          //返回栈中元素的个数
  3. s.top();           //返回栈顶元素, 但不删除该元素
  4. s.pop();           //弹出栈顶元素, 但不返回其值
  5. s.push();          //将元素压入栈顶

(1)基于数组的栈

  1. #include <stack>
  2. #include <iostream>
  3. using namespace std;
  4.  
  5. int main()
  6. {
  7.     stack<int> mystack;
  8.     int sum = 0;
  9.     for (int i = 0; i <= 10; i++){
  10.         mystack.push(i);
  11.     }
  12.     cout << "size is " << mystack.size() << endl;
  13.     while (!mystack.empty()){
  14.         cout << " " << mystack.top();
  15.         mystack.pop();
  16.     }
  17.     cout << endl;
  18.     system("pause");
  19.     return 0;
  20. }

//size is 11
// 10 9 8 7 6 5 4 3 2 1 0
(2)基于单链表的栈

  1. #include <iostream>
  2. using namespace std;
  3. template<class T>class Stack
  4. {
  5. private:
  6.     struct Node
  7.     {
  8.         T data;
  9.         Node *next;
  10.     };
  11.     Node *head;
  12.     Node *p;
  13.     int length;
  14.  
  15. public:
  16.     Stack()
  17.     {
  18.         head = NULL;
  19.         length = 0;
  20.     }
  21.     void push(T n)//入栈
  22.     {
  23.         Node *q = new Node;
  24.         q->data = n;
  25.         if (head == NULL)
  26.         {
  27.             q->next = head;
  28.             head = q;
  29.             p = q;
  30.         }
  31.         else
  32.         {
  33.             q->next = p;
  34.             p = q;
  35.         }
  36.         length++;
  37.     }
  38.  
  39.     T pop()//出栈并且将出栈的元素返回
  40.     {
  41.         if (length <= 0)
  42.         {
  43.             abort();
  44.         }
  45.         Node *q;
  46.         T data;
  47.         q = p;
  48.         data = p->data;
  49.         p = p->next;
  50.         delete(q);
  51.         length--;
  52.         return data;
  53.     }
  54.     int size()//返回元素个数
  55.     {
  56.         return length;
  57.     }
  58.     T top()//返回栈顶元素
  59.     {
  60.         return p->data;
  61.     }
  62.     bool isEmpty()//判断栈是不是空的
  63.     {
  64.         if (length == 0)
  65.         {
  66.             return true;
  67.         }
  68.         else
  69.         {
  70.             return false;
  71.         }
  72.     }
  73.     void clear()//清空栈中的所有元素
  74.     {
  75.         while (length > 0)
  76.         {
  77.             pop();
  78.         }
  79.     }
  80. };
  81. int main()
  82. {
  83.     Stack<char> s;
  84.     s.push('a');
  85.     s.push('b');
  86.     s.push('c');
  87.     while (!s.isEmpty())
  88.     {
  89.         cout << s.pop() << endl;
  90.     }
  91.     system("pause");
  92.     return 0;
  93. }

练习1、实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。

          解法参考博客:https://blog.csdn.net/cherrydreamsover/article/details/79475925,具体过程如下:

(1)使用两个栈,一个栈用来保存当前的元素,记做:stackData,一个栈用来保存压入操作每一步的最小元素,记做:stackMin。

(2)入栈:当stackData栈中压入一个数据时,判断satckMin中是否为空。若为空,将该元素压入stackMin栈中。若不空,判断两者之间的大小,当前者小于或等于后者时,将前者中的数据压入后者中;当前者大于后者时,

不进行任何操作。

(3)出栈:保证stackMin中栈顶的元素是stackData中最小的。

#include<iostream>  
#include <stack>  
#include <cassert>  
using  namespace std;
 
//方法一:  一个辅助栈,如果这个栈为空,直接将元素入这个栈,如果辅助栈中有元素,将压入的元素和辅助栈顶元素比较,  
//压入两者中较小的那个元素使得辅助栈总是维持栈顶元素为最小值。  
//class Stack  
//{  
//public:  
//  void Push(int data)  
//  {  
//      stackData.push(data);  
//      if (stackMin.empty())  
//      {  
//          stackMin.push(data);  
//      }  
//      else  
//      {  
//          int tmp = stackMin.top();  
//          int min = data > tmp ? tmp : data;  
//          stackMin.push(min);  
//      }  
//  }  
//  
//  void Pop()  
//  {  
//      assert(!stackData.empty() && !stackMin.empty());  
//      stackData.pop();  
//      stackMin.pop();  
//  }  
//  
//  int GetMin()  
//  {  
//      assert(!stackMin.empty());  
//      return stackMin.top();  
//  }  
//  
//private:  
//  stack<int> stackData;  
//  stack<int> stackMin;  
//};  
 
//方法二: 一个辅助栈,如果这个栈为空,直接将元素入这个栈,如果辅助栈中有元素,将压入的元素和辅助栈顶元素比较,  
//如果压入的元素小于等于辅助栈顶元素,者将这个元素入辅助栈,否则无操作,出栈的时候判断要出栈的元素是否等于辅助  
//栈顶元素,如果是,也将辅助栈顶元素出栈。否则无操作。  
class Stack
{
public:
    void Push(int data)
    {
        stackData.push(data);
        if (stackMin.empty())
        {
            stackMin.push(data);
        }
        else
        {
            if (data <= stackMin.top())
            {
                stackMin.push(data);
            }
        }
    }
 
    void Pop()
    {
        assert(!stackData.empty() && !stackMin.empty());
        if (stackData.top() == stackMin.top())
        {
            stackMin.pop();
        }
        stackData.pop();
    }
 
    int GetMin()
    {
        assert(!stackMin.empty());
        return stackMin.top();
    }
 
private:
    stack<int> stackData;
    stack<int> stackMin;
 
};
 
 
int main()
{
    Stack s;
    //s.Push(5);  
    s.Push(36);
    s.Push(15);
    s.Push(95);
    s.Push(50);
    s.Push(53);
    cout << s.GetMin() << endl;
    system("pause");
    return 0;
}//15
(3)栈的应用举例

1)进制转换

2)括号匹配的检验

3)行编辑程序

4)迷宫求解、汉诺塔等经典问题

5)表达式求值

6)栈与递归的实现

 

练习2、剑指offer面试题30——包含min函数的栈

题目描述
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
class Solution {
public:
    stack<int> stackData;//保存数据用的栈stackData
    stack<int> stackMin;//保存最小的数的栈stackMin,其中它的栈顶始终为最小的数
    void push(int value) {
        stackData.push(value);
        if(stackMin.empty()) 
            stackMin.push(value);//如果stackMin为空,则value是最小的值,入栈
        else{
            if(stackMin.top()>=value) 
                stackMin.push(value);//否则当value小于等于stackMin的栈顶元素时,入栈(等于的时候也入栈是因为我考虑有相同的数)
        }
  }
  void pop() {
      if(stackData.top()==stackMin.top())//如果出栈的数刚好是最小的数,那么stackMin也应该出栈
        stackMin.pop();
      stackData.pop();
  }
  int top() {
    return stackData.top();//栈顶元素应返回stackData的栈顶元素
  }
  int min() {
    return stackMin.top();//stackMin的栈顶元素即是最小的数
  }
};
运行结果:

练习3、剑指offer面试题31——栈的压入、弹出序列

       参考博客:https://blog.csdn.net/budf01/article/details/76232497,解题思路为:创建一个栈进行压入、弹出操作。具体操作如下: 
(1)当栈为空或者栈顶元素和popV当前元素不相等时,将pushV当前元素压入; 
(2)当栈顶元素与popV当前元素相等时,将栈顶元素弹出,并移至popV下一个元素; 
(3)如果需要压入的元素个数大于pushV的元素个数,说明popV不可能是pushV的弹出序列。

代码为:

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        //特殊输入测试
        if(pushV.empty() || popV.empty() || pushV.size()!=popV.size())
            return false;
        stack<int> mystack;//定义一个辅助栈
        int index=0;
        for(int i=0;i<popV.size();i++){
            //当辅助栈为空或者栈顶元素和popV当前元素不相等时,将pushV当前元素压入
            while(mystack.empty()||mystack.top()!=popV[i]){
                if(index>=pushV.size())
                    //如果需要压入的元素个数大于pushV的元素个数,说明popV不可能是pushV的弹出序列
                    return false;
                mystack.push(pushV[index++]);
            }
            //当栈顶元素与popV当前元素相等时,将栈顶元素弹出,并移至popV下一个元素
            if(mystack.top()==popV[i])
                mystack.pop();
        }
        return true;
    }
};
运行结果:

 

 

当然可以利用其他思想解决,如引入哈希或直接利用向量的方式求解。

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        if(pushV.empty() && popV.empty() && pushV.size() != popV.size()){
            return false;
        }
        map<int,int> Hash; //用map做一个映射,入栈顺序的值不一定是递增  
        for(int i=0;i<pushV.size();i++){
            Hash[pushV[i]]=i+1;
        }
        int now=Hash[popV[0]]; //当前最靠后入栈的键值,例如题目给的4 3 5 1 2,now先等于4,再等于5
        for(int i=0;i<popV.size();i++){
        //如果入栈序列中没有这个值
            if(Hash[popV[i]]==0){
                return false;
            }
            if(Hash[popV[i]]>=now){
            now=Hash[popV[i]];
            }
            else if(Hash[popV[i]]<=Hash[popV[i-1]]){
                continue ;
            }
            else{
                return false;
            }
        }
        return true;
    }
};
练习4、简单的括号匹配判断

       例如,爱奇艺的一道实习在线编程题:当输入为()(())(),返回true;当输入为)()()()()),返回false,时间15min。(不能使用栈)

1、假设可以使用栈(15min可以完成)

C++代码:

#include <iostream>
#include <stack>
#include <vector>
using namespace std;
 
bool isRight(vector<char> &vec){
    stack<char> stack1;
    bool index = false;
    if (vec.size() <= 1 || vec[0]!='(' || vec.size()%2!=0){
        return index;
    }
    for (int i = 0; i < vec.size(); i++){
        if (vec[i] == '(')
            stack1.push(vec[i]);
        else if (vec[i] == ')')
            stack1.pop();
    }
    if (stack1.empty())
        index = true;
    return index;
}
 
int main(){
    //输入不定长的括号
    vector<char> vec;
    char tmpCh;
    char t;
    cout << "输入一串括号为:";
    do{
        cin >> tmpCh;
        vec.push_back(tmpCh);
    } while ((t = cin.get()) != '\n');
 
    //调用isRight函数
    bool myRes = isRight(vec);
    cout << myRes << endl;
    system("pause");
    return 0;
}
运行结果:

python代码:

def isRight(str1):
    index = False
    tmp = []
    if(len(str1)>=2 and len(str1)%2==0 and str1[0]=='('):
        for id in range(len(str1)):
            if str1[id] == '(':
                tmp.append(str1[id])
            else:
                tmp.pop()
        if len(tmp)==0:
            index = True
    return index
 
if __name__ == "__main__":
    try:
        while True:
            str1 = [i for i in input().split()]
            print(isRight(str1))  # 返回判断结果
    except:
        pass
运行结果:

2、不能使用栈(15min,不太好想,mad,笔试那会儿就没想到!)

       以下是我的想法,具体的过程如下:

      (1)由于不能使用栈,将左括号定义为数值1,右括号定义为数值-1,存放到向量id(C++)或列表tmp (Python)中;

      (2)初始化变量sum,用于判断总的求和结果是否等于0,若不等于0,则肯定不正确,若等于0,不一定正确;

      (3)循环遍历输入的括号向量vec,判断当前括号属性的同时,进行累加求和,如果求和值小于等于-1,break(跳出循环);

      (4)最后再检查sum是否等于0,此时若等于0,则为正确。

C++代码:

#include <iostream>
#include <vector>
using namespace std;
 
bool isRight(vector<char> &vec){
    vector<int> id(vec.size()); //用于存放左右括号的属性:左括号用1表示,右括号用-1表示
    int sum = 0;
    bool index = false;
    if (vec.size() <= 1 || vec[0]!='(' || vec.size()%2!=0){
        return index;
    }
    for (int i = 0; i < vec.size(); i++){
        if (vec[i] == '('){
            id.push_back(1);
            sum = id[i] + sum;
        }
            
        else if (vec[i] == ')'){
            id.push_back(-1);
            sum = id[i] + sum;
            if (sum <= -1)
                break;
        }
    }
 
    if (sum == 0)
        index = true;
    return index;
}
 
int main(){
    //输入不定长的括号
    vector<char> vec;
    char tmpCh;
    char t;
    cout << "输入一串括号为:";
    do{
        cin >> tmpCh;
        vec.push_back(tmpCh);
    } while ((t = cin.get()) != '\n');
 
    //调用isRight函数
    bool myRes = isRight(vec);
    cout << myRes << endl;
    system("pause");
    return 0;
}
运行结果同上

python代码:

def isRight(str1):
    index = False
    sum = 0
    tmp = []
    if(len(str1)>=2 and len(str1)%2==0 and str1[0]=='('):
        for id in range(len(str1)):
            if str1[id] == '(':
                tmp.append(1)
                sum += tmp[id]
            else:
                tmp.append(-1)
                sum += tmp[id]
                if sum<=-1:
                    break
        if sum == 0:
            index = True
    return index
 
if __name__ == "__main__":
    try:
        while True:
            str1 = [i for i in input().split()]
            print(isRight(str1))  # 返回判断结果
    except:
        pass
运行结果同上。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/569564
推荐阅读
相关标签
  

闽ICP备14008679号