重学数据结构--栈

370 阅读4分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

本系列文章为个人学习总结,如果有发现错误或存在疑问之处,欢迎留言指点!

本文是重学数据结构系列的第四篇,系列文章如下:
1.算法时间复杂度和空间复杂度
2.重学数据结构--链表
3.重学数据结构--队列
4.重学数据结构--栈
5.重学数据结构--树

1.介绍

  • 栈,英文名stack,它是一种先入后出的有序列表。
  • 栈是是一种插入删除只能在线性表听一端执行的特殊线性表。允许插入和删除的一端,为变化的一端,称为栈顶(Top),另一端为固定的一端,称为栈底(Bottom)
  • 最先放入栈中的元素在栈底,最后放入的元素在栈顶,而删除元素刚好相反,最后放入的元素最先删除,最先放入的元素最后删除。

下面分别为入栈和出栈示意图:

image-20200919225104684

image-20200919225151779

2.栈的快速入门

由于栈是一种有序列表,所以我们可以用数组或者链表来模拟栈,这里我们用数组模拟栈的相关操作。

数组模拟栈

思路

  • 定义数组用于存储数据
  • 定义一个top来表示栈顶,初始化为-1(表示栈内没有任何数据)
  • 入栈操作,当有数据加入到栈时,top++;stack[top] = data;
  • 出栈操作,int value = stack[top];top--;return value;

具体实现

/**
 * 数组模拟栈
 */
class ArrayStack{
    private Integer maxSize;
    private Integer stack[];
    private Integer top = -1;
​
    public ArrayStack(Integer maxSize) {
        this.maxSize = maxSize;
        stack = new Integer[maxSize];
    }
​
    //栈满(
    public boolean isFull(){
        return top == maxSize-1;
    }
​
    //栈空
    public boolean isEmpty(){
        return top == -1;
    }
​
    // 入栈
    public void push(Integer data){
        //判断栈是否满
        if(!isFull()){
            top++;
            stack[top] = data;
        }
    }
​
​
    // 出栈
    public Integer pop(){
        //判断栈是否为空
        if(isEmpty()){
            throw new RuntimeException("栈空,没有数据可出栈");
        }
        int value = stack[top--];
        return value;
    }
​
    // 遍历栈
    public void list(){
        //判断栈是否为空
        if(isEmpty()){
            System.out.println("栈空,没有数据~~~~");
            return;
        }
​
        for (int i = top; i >-1 ; i--) {
            System.out.printf("stack[%d]=%d\n",i,stack[i]);
        }
​
    }
}
​

测试:

    public static void main(String[] args) {
        ArrayStack stack = new ArrayStack(5);
        stack.push(2);
        stack.push(3);
        stack.push(4);
        stack.push(6);
        stack.push(7);
​
        stack.list();
        System.out.println();
        System.out.println("出栈的数据为:"+stack.pop());
        System.out.println();
​
        stack.list();
    }
}
​
​

3.Java中的队列

Java中的队列Queue顶级接口,源码如下:

public interface Queue<E> extends Collection<E> {
    /**
     *  添加一个元素到队列,如果队列容量满了,抛出异常IllegalStateException
     * Inserts the specified element into this queue if it is possible to do so
     * immediately without violating capacity restrictions, returning
     * {@code true} upon success and throwing an {@code IllegalStateException}
     * if no space is currently available.
     *
     * @param e the element to add
     * @return {@code true} (as specified by {@link Collection#add})
     * @throws IllegalStateException if the element cannot be added at this
     *         time due to capacity restrictions
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this queue
     * @throws NullPointerException if the specified element is null and
     *         this queue does not permit null elements
     * @throws IllegalArgumentException if some property of this element
     *         prevents it from being added to this queue
     */
    boolean add(E e);
​
    /**
     * 添加一个元素到队列,添加成功返回true,失败返回false   
     * Inserts the specified element into this queue if it is possible to do
     * so immediately without violating capacity restrictions.
     * When using a capacity-restricted queue, this method is generally
     * preferable to {@link #add}, which can fail to insert an element only
     * by throwing an exception.
     *
     * @param e the element to add
     * @return {@code true} if the element was added to this queue, else
     *         {@code false}
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this queue
     * @throws NullPointerException if the specified element is null and
     *         this queue does not permit null elements
     * @throws IllegalArgumentException if some property of this element
     *         prevents it from being added to this queue
     */
    boolean offer(E e);
​
    /**
     * 移除并返回队列头元素,如果队列为空抛出异常
     * Retrieves and removes the head of this queue.  This method differs
     * from {@link #poll poll} only in that it throws an exception if this
     * queue is empty.
     *
     * @return the head of this queue
     * @throws NoSuchElementException if this queue is empty
     */
    E remove();
​
    /**  
     * 移除并返回队列头元素,如果队列为空返回null
     * Retrieves and removes the head of this queue,
     * or returns {@code null} if this queue is empty.
     *
     * @return the head of this queue, or {@code null} if this queue is empty
     */
    E poll();
​
    /**
     * 返回队列头部元素,如果队列为空抛出异常
     * Retrieves, but does not remove, the head of this queue.  This method
     * differs from {@link #peek peek} only in that it throws an exception
     * if this queue is empty.
     *
     * @return the head of this queue
     * @throws NoSuchElementException if this queue is empty
     */
    E element();
​
    /** 返回列头元素,如果队列为空返回null
     * Retrieves, but does not remove, the head of this queue,
     * or returns {@code null} if this queue is empty.
     *
     * @return the head of this queue, or {@code null} if this queue is empty
     */
    E peek();
}

下层实现树如下图

image-20210418171945966

使用举例:

Queue<Integer> queue = new LinkedList<>();
​
// 入队
queue.add(1); // 队列容量满了,抛出异常
queue.offer(2); // 队列容量满了返回false
queue.add(3);
​
​
​
System.out.println(queue.peek()); // 出队不删除头部元素,队列空抛异常
System.out.println(queue.element()); //出队不删除头部元素,队列空返回null
System.out.println(queue.remove());  // 出队并删除头部元素,队列空抛异常
System.out.println(queue.poll());  // 出队并删除头部元素,队列空返回null
System.out.println(queue.poll());

4.Java中的栈

Java中没有对应的栈接口,但是有Stack类,它是基于Vector实现的。Java中使用栈更推荐使用Deque的实现类来完成栈的相关操作,因为Vector的相关方法都是加锁实现的,效率相对低。Deque中相关栈源码如下:

public interface Deque<E> extends Queue<E> {
    /**
         * 入栈   
     * Pushes an element onto the stack represented by this deque (in other
     * words, at the head of this deque) if it is possible to do so
     * immediately without violating capacity restrictions, throwing an
     * {@code IllegalStateException} if no space is currently available.
     *
     * <p>This method is equivalent to {@link #addFirst}.
     *
     * @param e the element to push
     * @throws IllegalStateException if the element cannot be added at this
     *         time due to capacity restrictions
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this deque
     * @throws NullPointerException if the specified element is null and this
     *         deque does not permit null elements
     * @throws IllegalArgumentException if some property of the specified
     *         element prevents it from being added to this deque
     */
    void push(E e);
​
    /**
     * 出栈
     * Pops an element from the stack represented by this deque.  In other
     * words, removes and returns the first element of this deque.
     *
     * <p>This method is equivalent to {@link #removeFirst()}.
     *
     * @return the element at the front of this deque (which is the top
     *         of the stack represented by this deque)
     * @throws NoSuchElementException if this deque is empty
     */
    E pop();
}

Deque继承了Queue类,其下层实现树如下图:

image-20210418171504969

使用举例如下:

public static void main(String[] args) {
        
        Deque<Integer> stack = new LinkedList<>();
        // 入栈
        for (int i = 0; i < 10; i++) {
            stack.push(i);
        }
        // 出栈
        while (!stack.isEmpty()){
            System.out.println(stack.pop());
        }
​
    }