数据结构之栈和队列

Posted lpeiNet

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构之栈和队列相关的知识,希望对你有一定的参考价值。

  其实栈和队列是特殊的线性表,特殊之处在于插入和删除的位置受到限制,如果插入和删除只在一端进行,那么这就是栈,如果插入在尾部进行,删除在头部进行就是队列,下面我们具体来看看栈和队列的实现。

1:栈

定义:栈是一种特殊的线性表,其插入和删除只能在一端进行,允许操作的一端叫做栈顶,不允许操作的一端叫做栈底。插入元素我们叫做进栈(push),删除元素我们叫做出栈(pop)。下面我们定义栈的接口

public interface SStack<T> {
    /**
     * 验证是否是空栈
     * @return
     */
    boolean isEmpty();

    /**
     * 进栈
     * @param x
     */
    void push(T x);

    /**
     * 出栈
     * @return
     */
    T pop();

    /**
     * 取栈顶元素
     * @return
     */
    T get();
}

2:顺序表实现栈

要实现栈,首先我们需要一个变量来记录栈顶的位置,这个变量我们设置top。我们定义top初始值为-1,也就是说当栈空的时候top就是-1。栈的特点就是先进后出,那么进栈就很简单了,我们只需要让top++即可,然后取得时候只需要去top对应的元素,后进去的就先出来,先进去的后出来。代码如下

private Object[] elements;
    private int top;//记录栈顶元素位置

    public SeqStack() {
        this(64);
    }

    public SeqStack(int size) {
        this.elements = new Object[size];
        this.top = -1;
    }

    public boolean isEmpty() {
        return this.top == -1;
    }

    public void push(T x) {
        if (x == null) {
            return;
        }
        if (this.top == this.elements.length - 1) {
            Object[] temp = this.elements;
            this.elements = new Object[2 * this.elements.length * 2];
            for (int i = 0; i < this.top; i++) {
                this.elements[i] = temp[i];
            }
        }
        this.top++;
        this.elements[this.top] = x;
    }

    public T pop() {
        return this.top == -1 ? null : (T) this.elements[this.top--];
    }

    public T get() {
        return this.top == -1 ? null : (T) this.elements[this.top];
    }

3:链式表实现栈

链式实现更新的简单了,同样我们只需要用一个头节点来记录栈顶即可,如果头节点为空说明是空栈,出栈的时候只需求去头节点,入栈的时候,把新元素赋值给头元素,头元素的后继节点为原先的头节点即可。代码如下

  public Node<T> top;
    public LinkedStack(){
        top=new Node<T>(null,null);
    }
    public LinkedStack(T[] elements) {
        if (elements == null) {
            return;
        }
        for (int i = 0; i < elements.length; i++) {
            this.top = new Node<T>(elements[i], this.top);
        }
    }

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

    public void push(T x) {
        if (x==null){
            return;
        }
        this.top=new Node<T>(x,this.top);
    }

    public T pop() {
        if (this.top != null) {
            T old = this.top.data;
            this.top = this.top.next;
            return old;
        }
        return null;
    }

    public T get() {
        return this.top == null ? null : this.top.data;
    }

4:栈的应用

我们经常写代码应该知道当我们写方法的时候少一个}编译器会立马报异常,现在我们考虑是如何实现的。

假设这个一个字符串,我们遇到{号的时候把它放入栈中,如果遇到}号的时候就出栈,如果出栈的是{则说明一对{}匹配成功,如果栈空,或者不是{表示缺少与}相匹配的{符合,如果最后栈不为null,说明缺少}号。我们来实现下。

 public static boolean isValid(String str) {
        SStack<Character> characterSStack = new SeqStack<Character>(str.length());
        boolean result=true;
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            switch (ch) {
                case ‘{‘:
                    characterSStack.push(ch);
                    break;
                case ‘}‘:
                    boolean a = characterSStack.isEmpty();
                    boolean b = characterSStack.get() != ‘{‘;
                    if (a || b) {
                        result = false;
                    }
                    characterSStack.pop();
                    break;
            }
            if (!result) {
                break;
            }
        }
        if (!characterSStack.isEmpty()) {
            result=false;
          }
        return result;
    }

 5:队列

队列我们说了只可以在队列和队尾操作,队尾我们加入元素,队列我们删除元素,没有元素我们称为空队列。下面先定义接口

public interface Queue<T> {
    /**
     * 验证队列是否为空
     * @return
     */
    boolean isEmpty();

    /**
     * 入队
     * @param x
     */
    void enQueue(T x);

    /**
     * 出队
     * @return
     */
    T deQueue();
}

6:顺序表实现队列

既然我们分别是在头和尾进行操作,那么我们就需要2个变量值来记录队列和队尾。我们分别用front、rear分别表示对列和队尾,如果我们加入第一个一个元素,rear和front都+1,其他的我们只需要rear+1,如果出对列同样我们让front+1,这样一来就满足我们的条件,但是问题是如果加入5个元素后rear=4,然后在出对列2个元素那么front=1;这样一来我们的队列就无法全部运用上,出现了假溢出。所以我们考虑采用循环的队列模式。具体实现如下

public class SeqQueue<T> implements Queue<T> {
    private Object[] elements;
    private int rear;//队尾
    private int front;//队头

    public SeqQueue() {
        this(64);
    }

    public SeqQueue(int length) {
        if (length <= 0) {
            return;
        }
        this.elements = new Object[length];
        this.front = rear = 0;
    }

    public boolean isEmpty() {
        return this.front == this.rear;
    }

    public void enQueue(T x) {
        if (x == null) {
            return;
        }
        if ((this.rear + 1) % this.elements.length == this.front) {
            Object[] temp = this.elements;
            this.elements = new Object[2 * this.elements.length * 2];
            int i = this.front, j = 0;
            while (i != this.rear) {
                this.elements[j] = temp[i];
                i = (i + 1) % temp.length;
                j++;
            }
            this.front = 0;
            this.rear = j;
        }
        this.elements[this.rear] = x;
        this.rear = (this.rear + 1) % this.elements.length;
    }

    public T deQueue() {
        if (this.isEmpty()) {
            return null;
        }
        T old = (T) this.elements[this.front % this.elements.length];
        this.front = this.front + 1 * this.elements.length;
        return old;
    }

7:链式实现对列

链式的就比较简单了,如果是队尾的话我们直接可以把rear的后继节点赋值为新元素,然后在把rear节点赋值为新元素。但是我们要考虑的是空表插入,这个时候就没有后继节点了,这个时候我们直接把新元素赋值给front即可。如果出队就更简单了,直接获取front即可。我们看下源码

public class LinkedQueue<T> implements Queue<T> {
    private Node<T> front;
    private Node<T> rear;

    public boolean isEmpty() {
        return this.front == this.rear && this.front == null;
    }

    public void enQueue(T x) {
        if (x == null) {
            return;
        }
        Node<T> p = new Node<T>(x, null);
        if (this.front == null) {
            this.front = p;
        } else {
            this.rear.next = p;
        }
        this.rear = p;
    }

    public T deQueue() {
        if (this.front == null) {
            return null;
        }
        T old = this.front.data;
        this.front = this.front.next;
        return old;
    }

 

以上是关于数据结构之栈和队列的主要内容,如果未能解决你的问题,请参考以下文章

剑指Offer数据结构之栈和队列[Python版]

数据结构之栈和队列及其Java实现

数据结构之栈和队列

数据结构之栈和队列

数据结构之栈和队列

Leetcode题解——数据结构之栈和队列