栈和队列(java)

一.栈

栈是限定仅在表尾进行插入和删除操作的线性表

允许插入和删除的一端称为栈顶(top),另一端称为栈底(bottom),不含任何数据元素的栈称为空栈。栈又称为后进先出的线性表


栈的顺序存储结构:如用数组实现,栈底是:下标为0的一端


栈的链式存储结构:


链栈的入栈操作:

链栈的出栈操作:

Stack和Vector

Stack继承Vector,是栈结构,他们本质还是数组

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    protected Object[] elementData;//数组放数据

    protected int elementCount;    //元素个数

    protected int capacityIncrement;//默认增量

    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }

    public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }

    public Vector() {
        this(10);
    }
public
class Stack<E> extends Vector<E> {
    /**
     * Creates an empty Stack.
     */
    public Stack() {
    }}
 
 

看看Stack的push方法:就是确定数组大小够用,不够扩容,在数组尾端加元素

    public E push(E item) {
        addElement(item);
        return item;
    }

    public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;     //elementCount++
    }

    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

peek:返回栈顶的元素(线性表尾端),而且不移除此元素。

栈里移除元素只需要把此元素设为null,ArrayList移除最后一个元素也是把数组尾端置null,但ArrayList移除其他索引的元素就得产生新数组复制元素,原因在于栈只能操作栈顶元素

    public synchronized E peek() {
        int     len = size();    //元素的个数

        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);
    }

    public synchronized E elementAt(int index) {
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
        }

        return elementData(index);
    }

    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

pop():弹出栈顶的元素

    public synchronized E pop() {
        E       obj;
        int     len = size();

        obj = peek();        //用peek找到栈顶元素
        removeElementAt(len - 1);

        return obj;
    }

    public synchronized void removeElementAt(int index) { //移除栈某个位置的元素
        modCount++;
        if (index >= elementCount) {
            throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                     elementCount);
        }
        else if (index < 0) {
            throw new ArrayIndexOutOfBoundsException(index);
        }
        int j = elementCount - index - 1;            //j>0说明想移除的不是栈顶 而是数组中间的元素,就采用数组复制的方法
        if (j > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, j);
        }
        elementCount--;
        elementData[elementCount] = null; /* to let gc do its work */    //移除元素,就是原栈顶处为null,并且elementCount--,这样下次往栈push元素 依然会在数组此位置放元素

    }

search:查询某个元素,从栈顶(数组尾端)往下遍历,返回索引

    public synchronized int search(Object o) {
        int i = lastIndexOf(o);

        if (i >= 0) {
            return size() - i;
        }
        return -1;
    }

    public synchronized int lastIndexOf(Object o) {
        return lastIndexOf(o, elementCount-1);
    }

    public synchronized int lastIndexOf(Object o, int index) {
        if (index >= elementCount)
            throw new IndexOutOfBoundsException(index + " >= "+ elementCount);

        if (o == null) {                        //数组的元素可以为null
            for (int i = index; i >= 0; i--)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = index; i >= 0; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }

栈的实例:逆波兰表达式法

标准四则运算表达式—中缀表达式:

计算机采用—后缀表达式:

后缀表达式如何计算:

中缀表达式转为后缀表达式:数字输出,运算符进栈,括号匹配出栈,栈顶优先级低出栈






二.队列

队列是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

插入的一端称为duan队尾,删除的一端称为队头


队列的顺序存储方式:front是队头,rear是队尾



顺序方式就会想到用数组,看图入队方便,但出队会让数组前几个元素置空,就会出现前面出现一节数组里是空的情况,即假溢出,浪费了存储空间。 这里就不能像栈一样置null就行,因为栈只在栈顶操作。

循环队列:头尾相接的顺序存储,可以解决假溢出的问题


队列的链式存储及结构模式:这是我们采用的队列实现方式




Queue:队列接口

public interface Queue<E> extends Collection<E> {

    boolean add(E e);

    boolean offer(E e);//这个是真正的入队操作

    E remove();

    E poll();//这个是出队操作

    E element();//获取元素

    E peek();
}

LinkedList 其实就实现了队列接口,Deque实现了Queue

public class LinkedList<E>
    extends AbstractSequentialList<E>
    implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{

    public boolean offer(E e) { //offer方法往队尾添加元素,跟链式线性表操作一样
        return add(e);
    }

    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
}

看出队操作:poll

    public E poll() {
        final Node<E> f = first;
        return (f == null) ? null : unlinkFirst(f);
    }

    private E unlinkFirst(Node<E> f) {//把原first节点所有置空,下个next节点置位first节点
        // assert f == first && f != null;
        final E element = f.item;
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }

看到了Deque接口定义了offerLast,offerFirst,pollLast等方法,LinkedList也实现了,就是从另外一端操作队列的方法,百度一下:

(deque,全名double-ended queue)是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。
双端队列是限定插入和删除操作在表的两端进行的线性表。这两端分别称做端点1和端点2。也可像栈一样,可以用一个铁道转轨网络来比喻双端队列。在实际使用中,还可以有输出 受限的双端队列(即一个端点允许插入和删除,另一个端点只允许插入的双端队列)和输入受限的双端队列(即一个端点允许插入和删除,另一个端点只允许删除的双端队列)。而如果限定双端队列从某个端点插入的元素只能从该端点删除,则该双端队列就蜕变为两个栈底相邻的栈了。
优缺点:尽管 双端队列 看起来似乎比栈和队列更灵活,但实际上在应用程序中远不及栈和队列有用。

三.

数据结构是描述数据间一种或多种特定关系的集合。

顺序表、链式表、栈、队列是数据结构,而ArrayList、LinkedList只是符合了这些数据结构的特点,就叫做他们的实现

猜你喜欢

转载自blog.csdn.net/u014203449/article/details/80142078