1. 程式人生 > >【資料結構】堆疊、佇列的原理及java實現

【資料結構】堆疊、佇列的原理及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());
    }
}