栈的初认识

什么是栈

        栈(stack)是一种数据结构,它是一种具有特定方法的线性表,又称之为访问受限的线性表,它是许多表达式,符号等运算的基础,也是递归的底层实现。。栈的特点是先进后出(FILO,First In Last Out),即最后进入的元素最先出来,而最先进入的元素最后出来。栈通常有两种基本操作:压栈(push),在栈顶插入元素;出栈(pop),删除栈顶元素。

        栈在计算机科学中有广泛的应用,比如函数调用的时候会使用栈来保存函数的调用顺序和局部变量;浏览器的访问历史可以使用栈来实现页面的后退和前进;编译器和解释器中使用栈来存储临时数据和函数调用栈;操作系统中也会使用栈来存储程序执行的上下文等。 栈的实现方式有多种,比如可以使用数组或链表来实现。栈的重要性不言而喻,它为解决许多实际问题提供了便利的途径。

栈的结构如下:

393a909794184c0c8bf89223fa4ceadf.png

栈的操作

        push():增加一个元素

        pop():弹出一个元素

        peek():显示栈顶元素,但是不出栈

        empty():判断栈是否为空

栈的实现

栈的实现可以用数组,也可以用链表,或者使用Java的LinkedList三种方式

用数组实现

#include <iostream>
#include <stack>

int main() {
    std::stack<int> myStack;

    // 压入元素
    myStack.push(1);
    myStack.push(2);
    myStack.push(3);

    // 访问栈顶元素并出栈
    std::cout << "栈顶元素:" << myStack.top() << std::endl;
    myStack.pop();

    // 输出栈中元素数量
    std::cout << "栈中元素数量:" << myStack.size() << std::endl;

    // 判断栈是否为空
    if(myStack.empty()) {
        std::cout << "栈为空" << std::endl;
    } else {
        std::cout << "栈不为空" << std::endl;
    }

    return 0;
}
import java.util.Stack;

public class StackExample {
    public static void main(String[] args) {
        Stack<Integer> myStack = new Stack<>();

        // 压入元素
        myStack.push(1);
        myStack.push(2);
        myStack.push(3);

        // 访问栈顶元素并出栈
        System.out.println("栈顶元素:" + myStack.peek());
        myStack.pop();

        // 输出栈中元素数量
        System.out.println("栈中元素数量:" + myStack.size());

        // 判断栈是否为空
        if(myStack.isEmpty()) {
            System.out.println("栈为空");
        } else {
            System.out.println("栈不为空");
        }
    }
}

 用链表实现

        用链表实现栈时,将插入与删除都在表头操作 

#include <iostream>

// 定义链表节点结构体
struct Node {
    int data;
    Node* next;
};

class Stack {
private:
    Node* top;

public:
    // 构造函数,初始化栈顶指针为nullptr
    Stack() : top(nullptr) {}

    // 判断栈是否为空
    bool isEmpty() {
        return top == nullptr;
    }

    // 压栈
    void push(int value) {
        Node* newNode = new Node;
        newNode->data = value;
        newNode->next = top;
        top = newNode;
    }

    // 出栈
    void pop() {
        if (isEmpty()) {
            std::cout << "栈为空,无法出栈" << std::endl;
            return;
        }
        Node* temp = top;
        top = top->next;
        delete temp;
    }

    // 获取栈顶元素
    int topValue() {
        if (isEmpty()) {
            std::cout << "栈为空,栈顶元素不存在" << std::endl;
            return -1;
        }
        return top->data;
    }

    // 析构函数,释放所有节点内存
    ~Stack() {
        while (top != nullptr) {
            Node* temp = top;
            top = top->next;
            delete temp;
        }
    }
};

int main() {
    Stack myStack;

    myStack.push(1);
    myStack.push(2);
    myStack.push(3);

    std::cout << "栈顶元素:" << myStack.topValue() << std::endl;
    myStack.pop();

    std::cout << "栈顶元素:" << myStack.topValue() << std::endl;
    myStack.pop();

    std::cout << "栈顶元素:" << myStack.topValue() << std::endl;
    myStack.pop();

    return 0;
}
import java.util.EmptyStackException;

class Node {
    int data;
    Node next;

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

class Stack {
    private Node top;

    public Stack() {
        top = null;
    }

    public boolean isEmpty() {
        return top == null;
    }

    public void push(int data) {
        Node newNode = new Node(data);
        newNode.next = top;
        top = newNode;
    }

    public int pop() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        int data = top.data;
        top = top.next;
        return data;
    }

    public int peek() {
        if (isEmpty()) {
            throw new EmptyStackException();
        }
        return top.data;
    }
}

public class Main {
    public static void main (String[] args) {
        Stack myStack = new Stack();

        myStack.push(1);
        myStack.push(2);
        myStack.push(3);

        System.out.println("栈顶元素:" + myStack.peek());
        myStack.pop();

        System.out.println("栈顶元素:" + myStack.peek());
        myStack.pop();

        System.out.println("栈顶元素:" + myStack.peek());
        myStack.pop();
    }
}

栈的经典算法

括号匹配问题

        当遇到左括号时,将其入栈;当遇到右括号时,检查栈顶元素是否与其匹配的左括号,如果匹配则将栈顶元素出栈,继续遍历;如果不匹配或者栈为空,则说明括号不匹配,返回 false。最终,若字符遍历结束时,栈为空,则说明括号完全匹配,返回 true。 

#include <iostream>
#include <stack>
#include <string>

bool isMatching(const std::string& str) {
    std::stack<char> st;
    
    for (char c : str) {
        if (c == '(' || c == '[' || c == '{') {
            st.push(c);
        } else if (c == ')' || c == ']' || c == '}') {
            if (st.empty()) {
                return false;
            } else if ((c == ')' && st.top() == '(') || (c == ']' && st.top() == '[') || (c == '}' && st.top() == '{')) {
                st.pop();
            } else {
                return false;
            }
        }
    }
    
    return st.empty();
}

int main() {
    std::string str = "{[()]}";
    if (isMatching(str)) {
        std::cout << "Parentheses are matching." << std::endl;
    } else {
        std::cout << "Parentheses are not matching." << std::endl;
    }

    return 0;
}

最小栈

        最小栈问题是一个常见的面试问题,通常要求设计一个特殊的栈数据结构,除了支持常规的栈操作(入栈、出栈、获取栈顶元素)之外,还要支持获取栈中的最小元素操作。即,设计一个栈,在常数时间复杂度内可以获取当前栈中的最小元素值。

#include <stack>
#include <iostream>

class MinStack {
private:
    std::stack<int> dataStack;
    std::stack<int> minStack;

public:
    void push(int x) {
        dataStack.push(x);
        if (minStack.empty() || x <= minStack.top()) {
            minStack.push(x);
        }
    }

    void pop() {
        if (dataStack.top() == minStack.top()) {
            minStack.pop();
        }
        dataStack.pop();
    }

    int top() {
        return dataStack.top();
    }

    int getMin() {
        return minStack.top();
    }
};

int main() {
    MinStack minStack;
    minStack.push(-2);
    minStack.push(0);
    minStack.push(-3);

    std::cout << "Current min element in stack: " << minStack.getMin() << std::endl;  // Output: -3

    minStack.pop();
    std::cout << "Top element in stack: " << minStack.top() << std::endl;  // Output: 0

    std::cout << "Current min element in stack: " << minStack.getMin() << std::endl;  // Output: -2

    return 0;
}

         在最小栈的实现中,dataStack 和 minStack 通常被用于存储不同类型的数据,并且它们之间具有一定的关系:

 `dataStack`:数据栈用于存储传入的用户数据,即用户对栈进行 push 和 pop 操作时真正操作的栈。数据栈中的元素顺序代表用户数据的入栈和出栈顺序。 

`minStack`:最小值栈(辅助栈)用于存储当前数据栈中的最小元素。当用户向数据栈压入元素时,如果该元素比当前最小元素小或等于当前最小元素,则要将该元素同时压入最小值栈。最小值栈中的栈顶元素始终代表当前数据栈中的最小元素。

        这种设计的关键在于,在常数时间内获取当前栈中的最小元素。通过在每次 push 操作中维护最小值栈的栈顶元素,最小值栈可以保持与数据栈相同的压入和弹出顺序,并在 O(1) 的时间内返回当前栈中的最小元素值。 因此,dataStack 和 minStack 是两个栈,互相独立,但在实现中具有密切的关系,最小值栈的设计是为了支持在常数时间内获取最小元素的特殊需求。

最大栈

与最小栈相似

#include <stack>
#include <iostream>

class MaxStack {
private:
    std::stack<int> dataStack;
    std::stack<int> maxStack;

public:
    void push(int x) {
        dataStack.push(x);
        if (maxStack.empty() || x >= maxStack.top()) {
            maxStack.push(x);
        }
    }

    void pop() {
        if (dataStack.top() == maxStack.top()) {
            maxStack.pop();
        }
        dataStack.pop();
    }

    int top() {
        return dataStack.top();
    }

    int getMax() {
        return maxStack.top();
    }
};

int main() {
    MaxStack maxStack;
    maxStack.push(2);
    maxStack.push(5);
    maxStack.push(1);

    std::cout << "Current max element in stack: " << maxStack.getMax() << std::endl;  // Output: 5

    maxStack.pop();
    std::cout << "Top element in stack: " << maxStack.top() << std::endl;  // Output: 5

    std::cout << "Current max element in stack: " << maxStack.getMax() << std::endl;  // Output: 2

    return 0;
}

计算器问题

        计算器问题通常是指实现一个简单的计算器程序,该程序可以对包含加减乘除以及括号的数学表达式进行求值。该问题的解决涉及到处理运算符优先级、括号的计算顺序以及实现逆波兰表达式等方法。解决计算器问题的最好方法就是栈。

#include <iostream>
#include <stack>
#include <string>

int calculate(std::string s) {
    std::stack<int> nums;
    std::stack<char> ops;

    int num = 0;
    char sign = '+';

    for (int i = 0; i < s.length(); i++) {
        char c = s[i];
        if (isdigit(c)) {
            num = num * 10 + (c - '0');
        }
        if ((!isdigit(c) && c != ' ') || i == s.length() - 1) {
            if (sign == '+') {
                nums.push(num);
            } else if (sign == '-') {
                nums.push(-num);
            } else if (sign == '*') {
                int prev = nums.top();
                nums.pop();
                nums.push(prev * num);
            } else if (sign == '/') {
                int prev = nums.top();
                nums.pop();
                nums.push(prev / num);
            }
            num = 0;
            sign = c;
        }
    }

    int result = 0;
    while (!nums.empty()) {
        result += nums.top();
        nums.pop();
    }
    return result;
}

int main() {
    // Example usage
    std::string s = "3+2*2";
    int result = calculate(s);
    std::cout << "Result: " << result << std::endl;  // Output: 7

    return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值