栈/队列常见面试算法题(C++实现)

栈: 先进后出

对于栈的算法题常见的技巧: 通过辅助栈实现排序,最小值搜索、元素位置交换。

同时注意栈的判空。

队列:先进先出

普通队列(数组构成的): 判空: 头指针==尾指针; 判满: 尾指针==n

对于生存者消费者模式: 常用阻塞队列。当队列满,等待队列阻塞,无法入队;当队列空,等待队列阻塞,队列不能出队。

循环队列: 为了充分利用队列空间。当尾指针指向最后一个位置,此时头指针也后移,新的元素无法入队。循环队列让数组首尾相连,当尾指针指向队尾,新的元素从数组第一个位置开始入队。(注意判空和判满)

1: 实现最小栈

思路: 建立两个栈,一个栈用来存放数据;一个栈用来存放当前最小栈。

最小栈就是: 栈底到栈顶,元素递减,栈底元素最大,栈顶元素最小。

class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
        // 构造函数 初始化最小栈
        my_min_stack.push(INT_MAX);
    }
    
    void push(int x) {
        my_stack.push(x);
        my_min_stack.push(::min(x, my_min_stack.top())); // 最小栈,元素逐渐变小, 因此取最小值。
    }
    
    void pop() { // 两者都要弹出来
        my_stack.pop();
        my_min_stack.pop();
    }
    
    int top() {
        return my_stack.top();
    }
    
    int min() {
        return my_min_stack.top();
    }
public:
    stack<int> my_stack;
    stack<int> my_min_stack; // 最小栈
};

2: 栈实现队列;

思路: 一个栈存放栈数据;一个栈存放队列数据。栈到队列是通过栈顶出栈压入另一个栈实现。

class CQueue {
public:
    stack<int> my_stack;
    stack<int> my_stack_queue;

public:
    CQueue() {
        ;
    }
    
    void appendTail(int value) {
        my_stack.push(value);
        return;
    }
    
    int deleteHead() {
        // 都没有元素
        if (my_stack_queue.empty() && my_stack.empty()) {
            return -1;
        }

        int res = 0;
        if (!my_stack_queue.empty()) {
            res = my_stack_queue.top();
            my_stack_queue.pop();
            return res;
        } 
        // 栈实现队列
        while (!my_stack.empty()) {
            my_stack_queue.push(my_stack.top());
            my_stack.pop();
        }

        res = my_stack_queue.top();
        my_stack_queue.pop();
        return res;  
    }

};

3: 有效的括号

思路:枚举判断是否符合有效的括号,符合就弹出栈顶,不符合就压入栈

class Solution {
public:
    bool isValid(string s) {
        // 声明一个栈
        stack<int> my_stack;

        for (int i = 0; i < s.size(); i++) {
            // 非空场景判断
            if (my_stack.empty()) {
                my_stack.push(s[i]);
                continue;
            }
            // () [] {} 只有这种场景是符合的,需要弹出栈顶元素的
            if ((s[i] == ')' && my_stack.top() == '(') ||
                (s[i] == '}' && my_stack.top() == '{') ||
                (s[i] == ']' && my_stack.top()  == '[') ) {
                my_stack.pop();
            } else {
                my_stack.push(s[i]);
            }
        }

        if (my_stack.empty()) return true;
        return false;
    }
};

4:  逆波兰表达式

思路:栈

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        // 声明一个栈
        stack<int> my_stack;
        int res = 0; 

        // 
        int tmp_val1 = 0;
        int tmp_val2 = 0;
        for (int i = 0; i <tokens.size(); i++) {
            if (i == 0 && my_stack.empty() && isNum(tokens[i])) {
                int tmp_val = atoi(tokens[i].c_str());
                my_stack.push(tmp_val);
                continue;
            }
            if (i >= 1 && isNum(tokens[i])) {
                my_stack.push(atoi(tokens[i].c_str()));
            } else {
                GetStackNum(tmp_val1, tmp_val2, my_stack);
                if (strcmp("+", tokens[i].c_str()) == 0) {
                    res = tmp_val1 + tmp_val2;
                    cout << res << endl;
                } else if (strcmp("-", tokens[i].c_str()) == 0) {
                    res = tmp_val2 - tmp_val1;
                } else if (strcmp("*", tokens[i].c_str()) == 0) {
                    res = tmp_val1 * tmp_val2;
                } else if (strcmp("/", tokens[i].c_str()) == 0) {
                    res = tmp_val2 / tmp_val1;
                }
                my_stack.push(res);
            }
        }
        return my_stack.top();
    }

    void GetStackNum(int& val1, int& val2, stack<int>& my_stack)
    {
        val1 = my_stack.top();
        my_stack.pop();
        val2 = my_stack.top();
        my_stack.pop();
    }


    int isNum(string& s)
    {
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '-' && s.size() != 1) {
                continue;
            }
            if (s[i] >= '0' && s[i] <= '9') {
                ;
            } else {
                return false;
            }
        }
        return true;
    }
};

5: 栈的排序

思路: 辅助栈,注意原栈一定是个从栈底到栈顶递减的栈,所以出栈到辅助栈,就是一个递增的,这样保证了原本的顺序。

class SortedStack {
public:
    stack<int> my_stack;
    stack<int> my_help_stack;

public:
    SortedStack() {
        ;
    }
    
    void push(int val) {
        if (my_stack.empty() || val <= my_stack.top()) {
            my_stack.push(val);
            return;
        }

        while (!my_stack.empty() && val > my_stack.top()) {
            my_help_stack.push(my_stack.top());
            my_stack.pop();
        }
        my_stack.push(val);
        while (!my_help_stack.empty()) {
            my_stack.push(my_help_stack.top());
            my_help_stack.pop();
        }
        return;
    }
    
    void pop() {
        if (my_stack.empty()) 
            return;
        my_stack.pop();
        return;
    }
    
    int peek() {
        if (my_stack.empty())
            return -1;
        return my_stack.top();
    }
    
    bool isEmpty() {
        return my_stack.empty();
    }

};

6: 栈转化为队列

思路: 

class MyQueue {
public:
    stack<int> my_stack;
    stack<int> my_queue;

public:
    /** Initialize your data structure here. */
    MyQueue() {
        ;
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        my_stack.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        if (my_queue.empty())
            StackToQueue(my_stack, my_queue);
        if (my_queue.empty())
            return -1;
        int res = my_queue.top();
        my_queue.pop();
        return res;
    }
    
    /** Get the front element. */
    int peek() {
        if (my_queue.empty())
           StackToQueue(my_stack, my_queue);
        if (my_queue.empty())
            return -1;
        return my_queue.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        if (my_queue.empty())
            StackToQueue(my_stack,my_queue);
        return my_queue.empty();
    }

private:
    void StackToQueue(stack<int>& s, stack<int>& q)
    {
        while (!s.empty()) {
            q.push(s.top());
            s.pop();
        }
        return;
    }

};

7: 化队列为栈

思路:在push时候进行 追加+反转

class MyStack {
public:
    queue<int> my_queue;
    queue<int> my_stack;

public:
    MyStack() {
        ;
    }
    
    void push(int x) {
        my_queue.push(x);
        QueueToStack(my_queue, my_stack);
    }
    
    int pop() {
        if (my_stack.empty())
            return -1;
        int res = my_stack.front();
        my_stack.pop();
        return res;
    }
    
    int top() {
        if (my_stack.empty())
            return -1;
        int res = my_stack.front();
        return res;
    }
    
    bool empty() {
        return my_stack.empty();
    }

private:
    void QueueToStack(queue<int>& q, queue<int>& s)
    {   
        // 将s数据放在q的后面,之后清空s
        while(!s.empty()) {
            q.push(s.front()); // 
            s.pop(); //
        }
        //对q和s互换反转,这样s就是一个和q存放顺序相反的
        swap(s, q);
    }    
};

8: 设计一个循环队列(用数组实现)

思路:

class MyCircularQueue {
public:
    vector<int> crc_que;  // 用数组来做队列(顺序队列)
    int head; // 头指针 指向队首 (出队列--头指针后移动)
    int tail; // 尾指针 指向队尾 (入队列--尾指针后移动)
    int num; //当前队列的元素个数
    int queue_size;

public:
    MyCircularQueue(int k) {
        crc_que.resize(k); // 重新初始化大小为k
        queue_size = k; // 数组队列的物理长度
        head = 0; 
        tail = 0;
        num = 0; 
    }
    
    bool enQueue(int value) {
        // 队列满 无法入队
        if (isFull())
            return false;
        // 当前尾指针存放数据
        crc_que[tail] = value; 
        num++;
        // 尾指针后移,循环队列,当走到队尾,就从头再开始。
        if ((tail + 1) == queue_size) {
            tail = 0;
        } else {
            tail = tail + 1; 
        }
        return true;
    }
    
    bool deQueue() {
        if (isEmpty())
            return false;
        // 头指针后移
        num--;
        if ((head + 1) == queue_size) {
            head = 0;
        } else {
            head = head + 1;
        }
        return true;
    }
    
    int Front() {
        // 头指针所指向的元素就是队首
        if (isEmpty())
            return -1;
        return crc_que[head];
    }
    
    int Rear() {
        // 尾指针前一个所指向的元素就是队尾元素
        if (isEmpty())
            return -1;
        if (tail == 0)  // 新的循环头 当前最后一个元素就在数组最后一个位置
            return crc_que[queue_size - 1];
        return crc_que[tail - 1];
    }
    
    bool isEmpty() {
        if (num == 0) {
            return true;
        }
        return false;
    }
    
    bool isFull() {
        // 当前队列的元素数量 = 容器的物理大小
        if (num == queue_size) {
            return true;
        }
        return false;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值