玩轉數據結構<二>棧和隊列

棧 Stack

  • 棧也是一種線性結構數組

  • 相比數組,棧對應的操做是數組的子集bash

  • 只能從一端添加元素,也只能從一端取出元素數據結構

  • 這一端稱爲棧頂app

  • 棧是一種後進先出的結構(Last In First Out LIFO)dom

  • 棧的應用編輯器

  • 無處不在的Undo操做(撤銷) ide

  • 程序調用的系統棧oop

棧的實現

  • 代碼實現性能

  • 接口代碼測試

public interface Stack<E> {
    int getSize();
    boolean isEmpty();
    void  push(E e);
    E pop();
    E peek();
}
複製代碼
  • 實現類
public class ArrayStack<E> implements Stack<E> {

    Array<E> array;

    public ArrayStack(int capacity){
        array = new Array<>(capacity);
    }

    public ArrayStack(){
        array = new Array<>();
    }

    @Override
    public int getSize() {
        return array.getSize();
    }

    @Override
    public boolean isEmpty() {
        return array.isEmpty();
    }

    @Override
    public void push(E e) {
        array.addLast(e);

    }

    @Override
    public E pop() {
        return array.removeLast();
    }

    @Override
    public E peek() {
        return array.getLast();
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append("Stack: ");
        res.append('[');
        for(int i = 0 ; i < array.getSize(); i++) {
            res.append(array.get(i));
            if (i != array.getSize() - 1) {
                res.append(",");
            }
        }
            res.append("] top");
            return res.toString();
        }


    public int getCapacity(){
        return array.getCapacity();
    }


}

複製代碼
  • 調用棧方法
ArrayStack<Integer> stack = new ArrayStack<>();
       for(int i = 0 ; i < 5 ; i++){
           stack.push(i);
           System.out.println(stack);
       }

       stack.pop();
       System.out.println(stack);
    }
複製代碼
  • 棧的時間複雜度分析

棧的應用

  • undo操做 - 編輯器
  • 系統調用棧 - 操做系統
  • 括號匹配 - 編譯器
class Solution{
    public boolean isValid(String s){
        Stack<Character> stack = new Stack<>();
        for(int i = 0 ; i < s.length(); i++){
            char c = s.charAt(i);
            if(c == '(' || c ==  '[' || c == '{'){
                stack.push(c);
            }else{
                if(stack.isEmpty()){
                    return false;
                }
                char topChar = stack.pop();
                if(c == ')' && topChar != '('){
                    return false;
                }
                 if(c == ']' && topChar != '['){
                    return false;
                }
                 if(c == '}' && topChar != '{(}'){
                    return false;
                }
            }
        } 
        return stack.isEmpty();
    }
}
複製代碼

隊列(Queue)

  • 隊列也是一種線性結構
  • 相比數組,隊列對應的操做是數組的子集
  • 只能從一端(隊尾)添加元素,只能從另外一端(隊首)去吃元素
  • 隊列是一種先進先出的數據結構(先到先得)
  • First In First Out (FIFO)

public class ArrayQueue<E> implements Queue<E> {

    private  Array<E> array;

    public  ArrayQueue(int capacity){
        array = new Array<>(capacity);
    }

    public  ArrayQueue(){
        array = new Array<>();
    }

    @Override
    public int getSize() {
        return array.getSize();
    }

    @Override
    public boolean isEmpty() {
        return array.isEmpty();
    }

    public int getCapacity(){
        return array.getCapacity();
    }

    @Override
    public void enQueue(E e) {
        array.addLast(e);
    }

    @Override
    public E dequeue() {
        return array.removeFirst();
    }

    @Override
    public E getFront() {
        return array.getFirst();
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append("Queue: ");
        res.append("front [");
        for(int i = 0 ; i < array.getSize(); i++) {
            res.append(array.get(i));
            if (i != array.getSize() - 1) {
                res.append(",");
            }
        }
        res.append("] tail");
        return res.toString();
    }

    public static void main(String[] args){
        ArrayQueue<Integer> queue = new ArrayQueue<>();
        for(int i = 0 ; i < 10 ; i++){
            queue.enQueue(i);
            System.out.println(queue);
            if(i % 3 == 2){
                queue.dequeue();
                System.out.println(queue);
            }
        }

    }
}


複製代碼

循環隊列

  • 代碼實現
public class LoopQueue<E> implements Queue<E> {

    private E[] data;
    private int front, tail;
    private int size;

    public  LoopQueue(int capacity){
        data = (E[])new Object[capacity + 1];
        front = 0;
        tail = 0;
        size = 0;
    }

    public  LoopQueue(){
        this(10);
    }
    public int getCapacity(){
        return data.length - 1;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return front == tail;
    }

    @Override
    public void enqueue(E e) {
            if((tail+1) % data.length == front){
                resize(getCapacity() * 2);
            }
            data[tail] = e;
            tail = (tail + 1)% data.length;
            size ++;
    }

    private void resize(int newCapacity){
        E[] newData = (E[]) new Object[newCapacity + 1];
        for(int i = 0;i < size ;i++){
            newData[i] =data[(front + i) % data.length];
        }
        data = newData;
        front = 0;
        tail = size;
    }

    @Override
    public E dequeue() {
        if(isEmpty()){
            throw new IllegalArgumentException("Cannot dequeue from an empty queue.");
        }
        E ret = data[front];
        data[front] = null;
        front =(front + 1) % data.length;
        size --;
        if(size == getCapacity()/4 && getCapacity() /2 != 0){
            resize(getCapacity() /2);
        }
        return ret;
    }

    @Override
    public E getFront() {
        if(isEmpty()){
            throw new IllegalArgumentException("Queue is empty.");
        }
        return data[front];
    }

    @Override
    public String toString(){
        StringBuilder res = new StringBuilder();
        res.append(String.format("Queue: size = %d , capacity = %d\n", size, getCapacity()));
        res.append(" front[" );
        for(int i = front ; i != tail ; i = ( i + 1 ) % data.length ){
            res.append(data[i]);
            if((i + 1) % data.length != tail){
                res.append(",");
            }
        }
        res.append("]tail");
        return res.toString();
    }

    public static void main(String[] args){
        LoopQueue<Integer> queue = new  LoopQueue<>();
        for(int i = 0 ; i < 10 ; i++){
            queue.enqueue(i);
            System.out.println(queue);
            if(i % 3 == 2){
                queue.dequeue();
                System.out.println(queue);
            }
        }

    }
}

複製代碼
  • loopQueue與ArrayQueue的性能對比
  • 代碼
public class Main {
    //測試使用q運行opCount個enqueue和dequeue操做所須要的時間,單位:秒
    private static double testQueue(Queue<Integer> q, int opCount){
        long startTime = System.nanoTime();
        Random random = new Random();
        for(int i = 0 ;i < opCount; i++){
            q.enqueue(random.nextInt(Integer.MAX_VALUE));
        }

        for(int i = 0 ;i < opCount; i++) {
            q.dequeue();
        }

        long endTime = System.nanoTime();
        return(endTime - startTime) / 1000000000.0;

    }
    public static void main(String[] args) {

      int opCount = 100000;

      ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();
      double time1 = testQueue(arrayQueue,opCount);
      System.out.println("ArrayQueue,time: "+ time1 +"s");
      LoopQueue<Integer> loopQueue = new LoopQueue<>();
      double time2 = testQueue(loopQueue,opCount);
      System.out.println("LoopQueue,time: "+ time2 +"s");

    }
}
複製代碼
  • 對比結果

相關文章
相關標籤/搜索