3.6 栈 ADT - 3.7 队列 ADT

3.6 栈 ADT

栈是限制插入和删除只能在一个位置上进行的表,叫做栈的顶部。对栈的基本操作有进栈和出栈,进栈在顶部插入元素,出栈删除最后插入的元素。
栈是一个表,因此任何实现表的方法都能实现栈。显然 ArrayList 和 LinkedList 都支持栈操作;因为栈操作是常数时间操作,除非在非常特殊的情形下,不能产生明显改进。

栈的链表实现

在表的顶端或末端插入来实现进栈,删除顶端或末端实现出栈。

栈的数组实现

在表的末端插入实现进栈,删除末端实现出栈。

栈的应用

平衡符号

编译器检查程序语法错误时,经常由于符号错误导致,大量诊断报错。因为每个右括号必然对应其相应的左括号如{([])}是合法的,[({)]}是不合法的。通过栈可以方便的检查符号:
一个空栈,从文件头部读入字符到文件尾。如果字符是左半部分则进栈,如果字符是右半部分,当栈空时报错,否则将左半部分出栈。如果出栈的符号不是对应的左半部分则报错。文件读完,栈非空则报错。

后缀表达式

使用科学计算器计算时对于乘除法优先于加减法的记法。例如:
3 × 5 + 4 + 9 ÷ 3 = 22 将被记录为 3 5 × 4 + 9 3 ÷ +
当见到一个数时,将其进栈,遇到一个运算符该运算符作用于出栈的两个数上。再讲所得结果进栈。就可以不必知道优先规则而直接计算。

中缀到后缀的转换

除了用了计算后缀表达式,栈同样可以将标准形式表达式(中缀表达式)转换为后缀式。
读到操作数时立即将其放到后缀式中,操作符则进入栈中(包括括号)。当栈中存在高优先级操作符,且下个操作符是低优先级时,将高优先级操作符出栈到后缀式,低优先级操作符进栈。左括号进栈后在遇到右括号前不出栈。读到有括号时则一直出栈直到左括号出栈。括号出栈时不添加到后缀式中。

3.7 队列 ADT

队列也是表,基本操作是入队,在队尾插入一个元素;出队,在队头删除一个元素。

队列的数组实现

队列的链表实现很简单。
下面是使用数组实现的队列,用到了循环数组,否则数组的空间将被很快耗尽。

public class MyArrayQueue<E> {

    private int front;
    private int back;
    private E[] queue;
    private int theSize;
    public static final int DEFAULT_CAPACITY = 10;

    public MyArrayQueue() {
        theSize = 0;
        ensureCapacity(DEFAULT_CAPACITY);
        front = queue.length / 2;
        back = front;
    }

    /**
     * 扩容数组的同时需要对队列进行拼接
     *
     * @param newCapacity 新数组长度2倍
     */
    public void ensureCapacity(int newCapacity) {
        if (newCapacity < theSize) {
            return;
        }
        E[] old = queue;
        queue = (E[]) new Object[newCapacity];
        if (back < front) {
            for (int i = front; i < theSize; i++) {
                queue[i] = old[i];
            }
            for (int i = 0; i < back + 1; i++) {
                queue[theSize + i] = old[i];
            }
            back = front + theSize - 1;
        } else {
            for (int i = 0; i < theSize; i++) {
                queue[i] = old[i];
            }
        }
    }

    public void enqueue(E e) {
        if (queue.length == theSize) {
            ensureCapacity(theSize * 2);
        }
        if (theSize != 0) {
            if (back == queue.length - 1) {
                back = 0;
            } else {
                back++;
            }
        }
        queue[back] = e;
        theSize++;
    }

    public E dequeue() {
        if (theSize == 0) {
            return null;
        }
        E returnVal = queue[front];
        if (front == queue.length - 1) {
            front = 0;
        } else {
            front++;
        }
        theSize--;
        return returnVal;
    }
}
posted @ 2020-08-10 01:00  PotatoTed  阅读(73)  评论(0)    收藏  举报