【數據結構】堆棧、隊列的原理及java實現

一、堆是一個運行時數據區,通過new等指令創建,不需要程序代碼顯式釋放
<1>優點:
可動態分配內存大小,生存週期不必事先告訴編譯器,Java垃圾回收自動回收不需要的數據;
<2>缺點:
運行時需動態分配內存,數據存取速度較慢。
如:

String str = new String(“abc”);
String str2 = new String(“abc”);

這裏寫圖片描述

二、棧(stack)又名堆棧,它是一種先進後出(FILO)的線性表。其限制是僅允許在表的一端進行插入和刪除運算。這一端被稱爲棧頂,相對地,把另一端稱爲棧底。向一個棧插入新元素又稱作進棧、入棧或壓棧,它是把新元素放到棧頂元素的上面,使之成爲新的棧頂元素;從一個棧刪除元素又稱作出棧或退棧,它是把棧頂元素刪除掉,使其相鄰的元素成爲新的棧頂元素。
<1>優點:
存取速度比堆快,僅次於寄存器,棧數據可以共享;
<2>缺點:
存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。

String str = “abc”;
String str2 = “abc”;

表的含義如下圖所示:
這裏寫圖片描述

這裏寫圖片描述

下面介紹兩種棧的實現方式:
1.採用鏈表中節點的方式實現:

public class MyStackNode<E> {

    Node<E> top = null;

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

    public void push(E data) {
        Node<E> newNode = new Node<E>(data);
        newNode.next = top;
        top = newNode;
    }

    public E pop() {
        if (this.isEmpty())
            return null;
        E data = top.data;
        top = top.next;
        return data;
    }

    public E peek() {
        if (isEmpty()) {
            return null;
        }
        return top.data;
    }
}

2.採用數組的方式實現:

public class MyStackArry<E> {
    private Object[] stack;
    private int size;

    public MyStackArry() {
        stack = new Object[10];
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public E peek() {
        if (isEmpty())
            return null;
        return (E) stack[size - 1];// 如果有元素就返回最後一個
    }

    /**
     * 移除棧頂部元素移除
     * 
     * @return
     */
    public E pop() {
        E e = peek();// 保存最後一個元素的備份
        stack[size - 1] = null;// 給數組最後一個元素賦null
        size--;
        return e;
    }

    /**
     * 把項壓入棧頂部
     * 
     * @param item
     * @return
     */
    public E push(E item) {
        ensureCapacity(size + 1);
        stack[size++] = item;
        return item;
    }

    /**
     * 檢查容量是否足夠,不夠再原有的數組基礎創建新的數組
     * 
     * @param size
     */
    public void ensureCapacity(int size) {
        int len = stack.length;
        if (size > len) {
            // int newLen = 10;
            // stack = Arrays.copyOf(stack, newLen);
            // 如果棧滿,則創建空間爲當前棧空間兩倍的棧
            Object[] temp = stack;
            stack = new Object[2 * stack.length];
            System.arraycopy(temp, 0, stack, 0, temp.length);
        }
    }

    /**
     * 返回對象在堆棧中的位置,以1 爲基數
     * 
     * @param o
     * @return
     */
    public int search(Object o) {
        int index = lastIndexOf(o);
        return index == -1 ? index : size - index;
    }

    /**
     * 查找下標的方法
     * 
     * @param o
     * @return
     */
    private int lastIndexOf(Object o) {
        if (isEmpty()) {
            throw new EmptyStackException(); // 如果數組爲空,就拋出一個自定義異常
        }
        // 當傳進來的元素爲空時
        if (o == null) {
            for (int i = size - 1; i >= 0; i--) {
                if (stack[i] == null) {
                    return i;
                }
            }
            // 不爲空時
        } else {
            for (int i = size - 1; i >= 0; i--) {
                if (o.equals(stack[i])) {
                    return i;
                }
            }
        }
        return -1; // 沒有找到,返回-1
    }

    // 自定義異常
    private static class EmptyStackException extends RuntimeException {
        public EmptyStackException() {
            super("堆棧爲空");
        }
    }

三、隊列 是一種先進先出的線性表。其限制僅在表的一端(尾端)進行插入,另一端(首端)進行刪除的線性表,先進先出FIFO。
這裏寫圖片描述
Quene類尚不在java集合框架中,因此它有很大的靈活性,爲了能夠進行代碼重用,我們試着通過繼承(is-a關係)或者合成(have-a關係)一些實現了List接口的類來定義Queue類。直觀的選擇是ArrayList和LinkedList。
1.第一種實現方式:LinkedList插入刪除效率比較高,可以實現隊列的尾部插入和頭部刪除只需常量次調用,我們首先選擇LinkedList來實現Queue。
這裏我們採用採用合成(have-a關係)的方法,通過包含一個LinkedList字段來定義一個Queue類。
實現方式如下:

public class MyQueueLink<E> {
    private LinkedList<E> list;

    public MyQueueLink() {
        list = new LinkedList<E>();
    }
   //入隊
    public  void put(E e) {
        list.addLast(e);
    }
   //出隊
    public  E pop() {
        return list.removeFirst();
    }

    public  boolean isEmpty() {
        return list.isEmpty();
    }

    public  int size() {
        return list.size();
    }
   //獲得隊列的第一個元素
    public  E front() {
        return list.getFirst();
    }
}

2.第二種可選擇的實現方式,用數組的方式實現

public class MyQueneArry {
    protected Object[] data;
    protected int size, head, tail;

    public MyQueneArry() {
        final int INTTIAN_LENGTH = 100;
        data = new Object[INTTIAN_LENGTH];
        size = 0;
        head = 0;
        tail = -1;
    }

    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    public Object front() {
        if (size == 0)
            throw new NoSuchElementException();
        return data[head];
    }
//入隊
    public void enquene(Object element) {
        if (size == data.length) {
            Object[] oldData = data;
            data = new Object[data.length * 2];
            System.arraycopy(oldData, head, data, 0, oldData.length - head);
            if (head > 0)
                System.arraycopy(oldData, 0, data, head + 1, tail - 1);
            head = 0;
            tail = oldData.length - 1;
        }
        tail = (tail + 1) % data.length;
        size++;
        data[tail] = element;
    }
//出隊
    public Object dequene() {
        if (size == 0)
            throw new NoSuchElementException();
        Object element = data[head];
        head = (head + 1) % data.length;
        return element;
    }

    public static void main(String[] args) {
        MyQueneArry q = new MyQueneArry();
        for (int i = 0; i < 18; i++) {
            q.enquene(i);
        }
        System.out.println("隊列長度:" + q.size());
        System.out.println("隊列首元素:" + q.dequene());
        System.out.println("隊列首元素:" + q.dequene());
    }
}
發佈了53 篇原創文章 · 獲贊 559 · 訪問量 88萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章