棧和隊列的相關算法題

棧和隊列是兩種非常重要的數據結構,都是邏輯結構,也就是說,棧(Stack),先進後出(後進先出),只要符合這種邏輯的數據結構都可以稱爲棧,隊列(Queue),先進先出(後進後出),只要符合這種邏輯結構的數據結構,都可以稱爲隊列。java中,有Stack這個類,但是很少用,因爲它底層使用的是Vector(和ArrayList基本一樣,唯一不同的是,裏面的方法是synchronized修飾的,因此是線程安全的,但是效率低,所以很少用),大部分情況都是使用LinkedList作爲棧和隊列,具體用法可以看LinkedList用作棧和隊列

1 用數組實現棧

定義一個top,指向棧頂元素,size,記錄棧中元素個數,當往棧中放一個元素,top++,size++,從棧中取出一個元素,- -top,並返回arr[top],size- -。

代碼

//用數組結構實現大小固定的隊列和棧
public  class Stack{
    public Integer[] arr;
    public Integer size;
    public Integer top;
    public Stack(int initSize){
        if(initSize < 0){
            throw  new IllegalArgumentException("The init size is less than 0");
        }
        arr = new Integer[initSize];
        size = 0;
        top = 0;
    }
    public void push(int i){
        if(size > arr.length - 1){
            throw  new ArrayIndexOutOfBoundsException("this stack is full");
        }
        arr[top++] = i;
        size++;
    }
    public Integer pop(){
        if(size == 0){
            throw new ArrayIndexOutOfBoundsException("this stack is empty");
        }
        size--;
        return arr[--top];
    }
    public Integer peek(){
        if(size == 0){
            return null;
        }
        return arr[top-1];
    }
}

2 用數組實現隊列

定義一個first、一個last指針,first指向隊首元素,last指向隊尾元素。向隊列中添加元素時,將元素添加到數組索引爲last的位置,之後,判斷last是否等於arr.length - 1,等於的話就讓last等於0,不等於就加1。從隊列中取出元素時,直接取出arr[first],之後,判斷first是否等於arr.length-1,等於的話就讓first等於0,不等於的話,就讓first加1。frist、last互不干擾。

代碼

 //用數組實現隊列
  public class Queue{
    Integer[] arr;
    Integer first;
    Integer last;
    Integer size;
    public Queue(int initSize){
        if(initSize < 0){
            throw new IllegalArgumentException("the init size is less than 0");
        }
        arr = new Integer[initSize];
        first = 0;
        last = 0;
        size = 0;
    }
    public void offer(Integer i){
        if(size >= arr.length){
            throw  new ArrayIndexOutOfBoundsException("this queue is full");
        }
        arr[last] = i;
        size++;
        //當數組滿的時候,就讓last指針爲0
        last = last == arr.length - 1 ? 0 : last + 1;
    }

    public Integer poll(){
        if(size == 0){
            throw new ArrayIndexOutOfBoundsException("this queue is empty");
        }
        int temp = arr[first];
        size--;
        //當first等於arr.length - 1 的時候,讓first等於0
        first = first == arr.length - 1 ? 0 : first + 1;
        return temp;
    }

    public Integer peek(){
        if(size == 0){
            return null;
        }
        return arr[first];
    }
}

2. 實現一個特殊的棧

實現一個特殊的棧,在實現棧的基本功能的基礎上,再實現返回棧中最小元素的操作。

【要求】

  1. pop、push、getMin操作的時間複雜度都是O(1)。
  2. 設計的棧類型可以使用現成的棧結構。

解題思路
定義兩個棧,一個棧用於存放所有數據,另一個輔助棧用來存放最小值,開始的時候,將第一個元素同時壓入兩個棧,之後,再壓入元素,第一個棧直接壓入,然後判斷這個元素是否比輔助棧中的棧頂元素小,小就壓入輔助棧,不小的話,就將輔助棧中的棧頂元素壓入。當彈出元素的時候,要同時彈出輔助棧中的棧頂元素。

public class Stack2{
        //定義兩個棧,第一個棧用來存放所有數據,第二個棧用來存放,當前數中的最小值
        Deque<Integer> stackData;
        Deque<Integer> stackMin;
        public Stack2(){
            stackData =  new LinkedList<>();
            stackMin = new LinkedList<>();
        }

        public void push(Integer i){
            //當向棧中壓入元素時,和最小值棧中的棧頂元素比,如果小於就壓入,大於的話
            // 就壓入最小值棧中棧頂元素
            if(stackMin.isEmpty()){
                stackMin.push(i);
            }else if(this.getMin() > i){
                stackMin.push(i);
            }else{
                stackMin.push(stackMin.peek());
            }
            stackData.push(i);
        }

        public Integer pop(){
            if(stackData.isEmpty()){
                throw new ArrayIndexOutOfBoundsException("this stack is empty");
            }
            stackMin.pop();
            return stackData.pop();
        }

        public Integer getMin(){
            if(stackMin.isEmpty()){
                throw new ArrayIndexOutOfBoundsException("this stack is Empty");
            }
            return stackMin.peek();
        }
    }

這道題還有一種解法是,只有當壓入的元素小於或者等於輔助棧棧頂元素的時候,才壓入輔助棧,否則不壓入,從棧中取出元素的時候,只有當取出的元素和輔助棧棧頂元素相等時,輔助棧纔會彈出棧頂元素。push()方法和pop()方法如下:

public void push(int newNum) {
	if (this.stackMin.isEmpty()) {
		this.stackMin.push(newNum);
	} else if (newNum <= this.getmin()) {
		this.stackMin.push(newNum);
	}
	this.stackData.push(newNum);
}

public int pop() {
	if (this.stackData.isEmpty()) {
		throw new RuntimeException("Your stack is empty.");
	}
	int value = this.stackData.pop();
	if (value == this.getmin()) {
		this.stackMin.pop();
	}
	return value;
}

3. 用棧實現隊列結構

用棧實現隊列結構,定義兩個棧stack1、stack2,stack1負責存數據,stack2負責彈出數據,向隊列中放數據時,直接將數據壓入stack1,從隊列中取出元素時,先判斷stack2是否爲空,不爲空的話,就彈出棧頂元素,爲空的話,就將stack1中的元素都壓入stack2,如果stack1也爲空的話,說明,隊列中沒有元素。

代碼

 public class TwoStackQueue{
   Deque<Integer> stack1;
    Deque<Integer> stack2;
    public TwoStackQueue(){
        stack1 = new LinkedList<>();
        stack2 = new LinkedList<>();
    }
    public void offer(Integer i){
        stack1.push(i);
    }

    public Integer poll(){
        if(stack2.isEmpty()){
            if(stack1 .isEmpty()){
                throw new RuntimeException("this queue is empty");
            }
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.pop();
    }

    public Integer peek(){
        if(stack2.isEmpty()){
            if(stack1 .isEmpty()){
                return null;
            }
            while(!stack1.isEmpty()){
                stack2.push(stack1.pop());
            }
        }
        return stack2.peek();
    }
}

4. 用隊列實現棧結構

隊列,先進先出,棧,先進後出。定義兩個隊列queue1、queue2,向棧中壓入數據時,直接將數據存到queue1中,從棧中取數據時,先將queue1中的數據存到queue2,只留最後一個數據在queue1中,彈出。之後,將queue2賦給queue1、將queue1賦給queue2,以便下次存或取數據。peek()操作和pop()操作類似,也是將queue1中的元素除最後一個以外都存到queue2,然後記錄這個值,再將最後一個元素存到queue2,交換queue1、queue2,最後返回剛記錄的那個值。

代碼

 public class TwoQueueStack {
    private Queue<Integer> queue;
    private Queue<Integer> help;
    public TwoQueueStack(){
        queue = new LinkedList<>();
        help = new LinkedList<>();
    }
    public void push(Integer i){
        queue.offer(i);
    }

    public Integer pop(){
        if(queue.isEmpty()){
            throw new RuntimeException("the stack is empty");
        }
        while(queue.size() != 1){
            help.offer(queue.poll());
        }
        int res = queue.poll();
        swap();
        return res;
    }

    public Integer peek(){
        if(queue.isEmpty()){
           return null;
        }
        while(queue.size() != 1){
            help.offer(queue.poll());
        }
        int res = queue.poll();
        help.offer(res);
        swap();
        return res;
    }

    public void swap(){
       Queue<Integer> temp = help;
       help = queue;
       queue = temp;
    }
}

5. 貓狗隊列

題目
實現一種貓狗隊列的結構,要求如下:
用戶可以調用offer方法將cat類或dog類的實例放入隊列中;
用戶可以調用pollAll方法,將隊列中所有的實例按照進隊列的先後順序依次彈出;
用戶可以調用pollDog方法,將隊列中dog類的實例按照進隊列的先後順序依次彈出;
用戶可以調用pollCat方法,將隊列中cat類的實例按照進隊列的先後順序依次彈出;
用戶可以調用isEmpty方法,檢查隊列中是否還有dog或cat的實例;
用戶可以調用isDogEmpty方法,檢查隊列中是否有dog類的實例;
用戶可以調用isCatEmpty方法,檢查隊列中是否有cat類的實例。

解題思路
定義兩個隊列,catQueue、dogQueue,catQueue用於存放Cat、dogQueue用於存放Dog,這樣pollDog、pollCat、isDogEmpty、isCatEmpty方法,都可以實現,再定義一個PetEnterQueue類,封裝Dog、Cat,並且加一個count屬性,來記錄dog、cat的順序,調用pollAll方法時,比較catQueue、dogQueue中的Pet的count屬性,誰小就先彈出誰。

代碼

public class Code_04_DogCatQueue {
    public static class Pet{
        private String type;
        public Pet(String type){
            this.type = type;
        }
        public String getType(){
            return type;
        }
    }
    public static class Dog extends Pet{
        public Dog(){
            super("dog");
        }
    }
    public static class Cat extends Pet{
        public Cat(){
            super("cat");
        }
    }
    public static class PetEnterQueue {
        private Pet pet;
        private Long count;
        public PetEnterQueue(Pet pet, Long count){
            this.pet = pet;
            this.count = count;
        }

        public Pet getPet() {
            return pet;
        }

        public Long getCount() {
            return count;
        }
    }

    public static class DogCatQue{
        private Deque<PetEnterQueue> dogQue;
        private Deque<PetEnterQueue> catQue;
        private Long count;
        public DogCatQue(){
            dogQue = new LinkedList<>();
            catQue = new LinkedList<>();
            count = 0l;
        }

        public void offer(Pet pet){
            if(pet.getType().equals("dog")){
                dogQue.offer(new PetEnterQueue(pet, count++));
            }else{
                catQue.offer(new PetEnterQueue(pet, count++));
            }
        }

        public Pet pollAll(){
            if(!catQue.isEmpty() && !dogQue.isEmpty()){
                if(dogQue.peek().getCount() > catQue.peek().getCount()){
                    return catQue.poll().getPet();
                }else{
                    return dogQue.poll().getPet();
                }
            } else if(catQue.isEmpty()){
                return dogQue.poll().getPet();
            } else if(dogQue.isEmpty()){
                return catQue.poll().getPet();
            }else{
                throw new RuntimeException("this DogCatQueue is empty");
            }
        }

        public Dog pollDog(){
            if(dogQue.isEmpty()){
                throw new RuntimeException("dog queue is empty");
            }else{
                return (Dog)dogQue.poll().getPet();
            }
        }

        public Cat pollCat(){
            if(catQue.isEmpty()){
                throw new RuntimeException("cat queue is empty");
            }else{
                return (Cat)catQue.poll().getPet();
            }
        }

        public boolean isEmpty(){
            return catQue.isEmpty() && dogQue.isEmpty();
        }

        public boolean isDogEmpty(){
            return dogQue.isEmpty();
        }

        public boolean isCatEmpty(){
            return catQue.isEmpty();
        }
 }  

如有不足之處,歡迎指正,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章