栈和队列总结:一篇搞懂栈和队列的实现和使用

目录

概念

操作

实现

队列

概念

操作

实现

 循环队列

双端队列Deque

Java中栈、队列、双端队列的使用

经典面试题

有效括号

用队列实现栈

用栈实现队列

实现最小栈

设计循环队列


概念

栈是一种特殊的线性结构,只允许在固定的一段进行插入和删除操作。

进行插入和删除操作的一端称为栈顶,另一端称为栈底。

栈中的元素遵循先进后出的原则。

操作

 入栈(压栈):栈的插入操作叫做入栈。入数据在栈顶

出栈:栈的删除操作。出数据也在栈顶

取栈顶元素:取出栈顶的元素。

实现

  1. 利用顺序表实现,使用尾插和尾删的方式实现
  2. 利用链表实现,在头尾都可以实现
public class MyStack {
    //利用顺序表实现
    private int[] array  = new int[100];//不考虑扩容,使用固定大小的数组
    private int size=0;

    public void push(int v){//入栈
        array[size++] = v;
    }

    public int pop(){//出栈
        return array[--size] ;
    }
    public int peek(){
        return array[size-1];//取出栈顶元素
    }
    public boolean isEmpty(){
        return size ==0;
    }
    public int size(){
        return size;
    }
}

队列

概念

在一端进行插入数据,在另一端进行数据删除操作的特殊的线性表。

队列具有先进先出(FIFO)的原则。

操作

入队列:在队尾(rear/tail)进行插入元素

出队列:在队头(front/head)进行删除操作

取出队首元素

实现

使用链表的结构实现队列

class Node{
    int val;
    Node next;

    public Node(int val, Node next) {
        this.val = val;
        this.next = next;
    }

    public Node(int val) {
        this.val = val;
    }
}
public class MyQueue {
    private Node head = null;
    private Node tail = null;
    private int size =0;
    public void offer(int v){//从队尾进行插入
        Node node = new Node(v);
        if (tail == null){
            head = node;
        }else {
            tail.next = node;
        }
        tail = node;
        size++;
    }
    public int poll(){//从队首进行删除
        if (size == 0){
            throw new RuntimeException("队列为空");
        }
        Node oldHead = head;
        head  =head.next;
        if (head == null){
            tail = null;
        }
        size--;
        return oldHead.val;//返回的是队首元素的值
    }
    public int peek(){//取出队首元素
        if (size == 0){
            throw new RuntimeException("队列为空");
        }
        return head.val;
    }
    public boolean isEmpty(){
        return size ==0;
    }
    public int size(){
        return size;
    }
}

 循环队列

循环队列通常使用数组实现

循环队列更好的利用了队列的存储空间,当插入到队尾时,如果队首元素已经出队,则从队首接着插入。

队列为空时:front = rear

队列为满时:(rear+1)%maxSize = front

循环队列的长度为:(rear - front + maxSize) % maxSize

双端队列Deque

双端队列是只允许两端都可以进行入队和出队操作的队列。

Deque是“Double ended Queue”的简称。

Java中栈、队列、双端队列的使用

Stack类提供的方法:

方法说明
E push (E e)入栈
E pop()

出栈

E peek()

查看栈顶元素

boolean empty()判断栈是否为空

 

Queue接口提供的方法:

针对异常的处理有两类方法——抛出异常,返回特殊值

 抛出异常返回特殊值

入队列

add(e)

offer(e)

出队列remove()

poll()

查看队首元素element()peek()

Deque接口继承自Queue,所以Queue接口有的方法,Deque接口也有。

 头部元素(队首)尾部元素(队尾)
 抛出异常返回特殊值抛出异常返回特殊值
入队列addFirst(e)offerFirst(e)addLast(e)offerLast(e)
出队列removeFirst()pollFirst()removeLast()pollLast()
查看队首元素getFirst()peekFirst()getLast()peekLast()

经典面试题

有效括号

https://leetcode-cn.com/problems/valid-parentheses/

思路:根据栈的先进后出的原则,进行括号的有效匹配。

  1. 准备一个栈,遍历字符串中的每个字符,遇到左括号就进栈
  2. 遇到右括号就取出栈顶元素进行匹配
    1. 如果栈为空,说明右括号多,返回false
    2. 如果不匹配,返回false
  3. 遍历完数组,如果栈中依然还有元素,说明左括号多余,返回false
public class Solution {
    public boolean isValid(String s) {
        Deque<Character> stack = new LinkedList<>();
        char[] charArray  = s.toCharArray();
        for(char c : charArray) {
            switch(c) {
                case '(':
                case '[':
                case '{':
                    stack.push(c);
                    break;
                default: {
                    if(stack.isEmpty()) {
                        return false;
                    }
                    char left = stack.pop();
                    if(!compareBracket(left ,c)) {
                        //左右括号不匹配
                        return  false;
                    }
                }
            }
        }
        if(stack.isEmpty()) {
            return true;
        } else {
            //证明是左括号多了
            return false;
        }
    }
//判断括号是否正确匹配
    private  boolean compareBracket (char left ,char right) {
        if(left == '(' && right == ')') {
            return  true;
        }
        if(left == '[' && right ==']') {
            return  true;
        }
        if(left == '{' && right == '}') {
            return  true;
        }
        return false;
    }
}

用队列实现栈

https://leetcode-cn.com/problems/implement-stack-using-queues/

思路:

push操作:直接添加到队列中。

pop操作:先将前size-1个元素,出队列,再入队列,最后删除队首元素。

top操作:top操作只是查看栈顶的元素,并不能改变改变原有的元素;先将前size-1个元素,出队列,再入队列,删除队首元素,再将队首元素添加到队列中去。

empty操作:只要判断队列是否为空即可。

pubilc class MyStack {
    Queue<Integer> queue = new LinkedList<>();
    public MyStack() {
        queue = new LinkedList<>();
    }

    public void push(int x) {
        queue.add(x);
    }
    
    public int pop() {
        int size = queue.size();
        for(int i = 0 ;i < size -1 ;i++) {
            Integer e = queue.remove();
            queue.add(e);
        }
        return queue.remove();
    }

    public int top() {
        int size = queue.size();
        for(int i = 0; i< size -1 ;i++) {
            Integer e  = queue.remove();
            queue.add(e);
        }
        Integer t =queue.remove();
        queue.add(t);
        return t;
    }
    
    public boolean empty() {
        return queue.isEmpty();
    }
}

用栈实现队列

https://leetcode-cn.com/problems/implement-queue-using-stacks/

思路:

使用两个栈来实现队列,压入栈s1和输出栈s2;

pop和peek操作,只要输出栈为空,就将压入栈s1中的元素全部压入s2,最后返回s2的栈顶栈顶元素即可。

class MyQueue {
    private Deque<Integer> s1;
    private Deque<Integer> s2;

    public MyQueue() {
        s1 = new LinkedList<>();
        s2 = new LinkedList<>();
    }
    

    public void push(int x) {
        s2.push(x);
    }
    

    public int pop() {
        if (s1.isEmpty()) {
            while (!s2.isEmpty()) {
                Integer e = s2.pop();
                s1.push(e);
            }
        }

        return s1.pop();
    }
    
   public int peek() {
        if (s1.isEmpty()) {
            while (!s2.isEmpty()) {
                Integer e = s2.pop();
                s1.push(e);
            }
        }

        return s1.peek();
    }
    
    public boolean empty() {
        return s1.isEmpty() && s2.isEmpty();
    }
}

实现最小栈

https://leetcode-cn.com/problems/min-stack/solution/zui-xiao-zhan-by-leetcode-solution/

思路:设计一个辅助栈,与元素同步插入与删除,用于存储每个元素的最小值

元素e要入栈时,取辅助栈的栈顶元素与e比较,得出最小值,及那个最小值插入辅助栈;

元素e要出栈时,辅助栈的元素一并弹出;

栈内元素的最小值就是辅助栈的栈顶元素。

class MinStack {
    private Deque<Integer> s1;
    private Deque<Integer> s2;

    public MinStack() {
        s1 = new LinkedList<>();
        s2 = new LinkedList<>();
    }
    
    public void push(int x) {
        s1.push(x);
        if(s2.isEmpty()) {
            s2.push(x);
        } else {
            int t = s2.peek();
            if(x < t) {
                s2.push(x);
            } else {
                s2.push(t);
            }
        }
    }
    
    public void pop() {
        s1.pop();
        s2.pop();
    }
    
    public int top() {
        return s1.peek();
    }
    
    public int getMin() {
        return s2.peek();
    }
}

设计循环队列

https://leetcode-cn.com/problems/design-circular-queue/

思路:

使用数组,通过操作数组的索引来实现循环。

class MyCircularQueue {
    private final int[] array;
    private int size;
    private int frontIndex;
    private int rearIndex;
    //构造函数
    public MyCircularQueue(int k) {
        array = new int[k];
        size =0;
        frontIndex = 0;
        rearIndex =  0;
    }    
 
    //向循环队列中插入元素
    public boolean enQueue(int value) {
        if(size == array.length) {
            return false;
        }
        array[rearIndex] = value;
        size++;
        rearIndex++;
        //循环
        if(rearIndex == array.length) {
            rearIndex =0;
        }
        return true;
    }

    //删除元素
    public boolean deQueue() {
        if(size == 0) {
            return false;
        }
        size--;
        frontIndex++;
        if(frontIndex == array.length) {
            frontIndex =0;
        }
        return true;
    }
    
    public int Front() {
        if(size == 0) {
            return -1;
        }
        return array[frontIndex];
    }
    
    public int Rear() {
        if(size == 0) {
            return -1;
        }
        int index = rearIndex -1;
        if(index == -1) {
            index = array.length -1;
        }
        return array[index];
    }

    public boolean isEmpty() {
        return size == 0;
    }
    
    public boolean isFull() {
        return size == array.length;
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值