数据结构学习笔记之栈和队列

一. 栈
  1. 介绍
      栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅能在表尾进行插入和删除操作。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
      栈是一种后进先出(Last In First Out LIFO)的数据结构。

  栈在计算机中有着不可思议的作用,比如撤销(Undo)操作、java程序调用的虚拟机栈、临时存储运算数据的操作数栈等等。

  1. 实现
public interface Stack {
    //将元素入栈
    public void push(E item) ;
    //将元素出栈
    public  E pop() ;
    // 获取栈顶元素
    public  E peek() ;
    // 栈是否为空
    public boolean isEmpty();
}
//我们可以使用之前自定义的数组方式实现,只需要每次都从尾部添加和移除元素即可。
public class ArrayStack implements Stack {
    private Array array = new Array<>();
    @Override
    public void push(E item) {
        array.addLast(item);
    }
    @Override
    public E pop() {
        return array.removeLast();
    }
   ......
}
二. 队列
  1. 定义
      队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
入队和出队操作

  队列是一种先进先出(First In First Out)的线性结构。

  1. 实现
public interface Queue {
    //获得 队列中的元素个数
    int getSize();
    // 队列是否为空
    boolean isEmpty();
    //入队
    void enqueue(E e);
    //出队
    E dequeue();
    //获得队首元素
    E getFront();
}
//同样,我们可以使用之前自定义的动态数组完成队列的实现,只需要向数组尾部添加元素,从数组头部获取即可
public class ArrayQueue implements Queue {
    private Array array = new Array<>();

    @Override
    public void enqueue(E e) {
        array.addLast(e);
    }

    @Override
    public E dequeue() {
        return array.removeFirst();
    }
    ......
}
  1. 扩展
      我们使用数组实现队列时,在出队时,由于移除的是数组中第一个位置的元素,所以会导致数组的其他元素往左移,使得出队的时间复杂度变为 O(n)。
      所以我们可以将数组看做成一个环,在元素出队时不进行元素的移动,而是修改队首的指针;而在入队时,当数组的右侧已经无法容纳元素时,在扩容之前会首先寻找数组的左侧是否有空闲的位置,如果有出队的操作,则表示有空闲的位置,我们直接将入队的元素放置到数组的左侧,如果没有空闲的位置,则进行扩容。具体流程如下:
入队和出队操作
public class LoopQueue implements Queue{
    private T[] data;
    private int font;
    private int tail;
    private int size;
    public LoopQueue(int cap){
        data = (T[])new Object[cap + 1];
    }
    @Override
    public void enqueue(T t) {
        //按照图中描述, 当 (tail + 1) % n = font 进行扩容
        if((tail + 1) % data.length == font) resize(data.length * 2);
        // 放置元素, 修改 tail 指向
        data[tail] = t;
        tail = (tail + 1)% data.length;
        size ++;
    }

    @Override
    public T dequeue() {
        if(size == 0) return null;
        //出队,修改 font 指针指向
        T ret = data[font];
        font = (font + 1)% data.length;
        size -- ;
        return ret;
    }
    private void resize(int newcap){
        T[] newArr =(T[]) new Object[newcap];
        int len = data.length;
        for (int i = 0; i <= size; i++) {
            newArr[i] = data[(font + i) % len];
        }
        this.data = newArr;
        font = 0;
        tail = size;
    }
}
代码地址

你可能感兴趣的:(数据结构学习笔记之栈和队列)