A stack and queue are implemented with a fixed size array
1. Implement stack structure with fixed size array
package com.offer.class3; /** * Fixed array implementation stack structure */ public class StackWithArray { private int[] arr; private int index; // Point to the location where the element will be placed public StackWithArray(int initialSize){ if(initialSize < 0){ throw new IllegalArgumentException("the init size is less than 0"); } arr = new int[initialSize]; index = 0; } // Stack pressing public void push(int obj){ if(index == arr.length){ throw new ArrayIndexOutOfBoundsException("the stack is full!"); } arr[index++] = obj; // index refers to the current location where data is to be stored } // Pop up stack (delete element) public int pop(){ if(index == 0){ throw new ArrayIndexOutOfBoundsException("the stack is empty!"); } return arr[--index]; // The previous element pointed to by index is deleted, because index points to an empty position } // Pop up elements without deleting them public int peek(){ if(index == 0){ throw new ArrayIndexOutOfBoundsException("the stack is empty!"); } return arr[index - 1]; // The index did not decrease, so the element at the index position was not deleted } }
2 fixed size array implementation queue
Note: the actual meaning of start, end and size variables. The size variable realizes the decoupling between start and end variables.
package com.offer.class3; /** * Fixed array implementation queue * Three variables: start, end, size */ public class QueueWithArray { private int start; // Point to the head of the team and the location of the data to be retrieved each time private int end; // Point to the end of the queue where you want to add data each time private int size; // The number of elements in the queue. Use size to decouple start and end private int[] arr; public QueueWithArray(int initialSize){ if(initialSize < 0){ throw new IllegalArgumentException("the initialSzie is less than 0"); } arr = new int[initialSize]; start = 0; end = 0; size = 0; } // Add an element public void push(int obj){ if(size == arr.length){ throw new ArrayIndexOutOfBoundsException("the queue is full"); } size++; arr[end] = obj; // If end points to the position of the last element in the array, you need to jump to the starting position and start from scratch end = (end == arr.length - 1) ? 0 : end + 1; } public int poll(){ if(size == 0){ throw new ArrayIndexOutOfBoundsException("the queue is empty"); } size--; int tmp = start; start = (start == arr.length - 1) ? 0 : start + 1; return arr[tmp]; } }
Second, the stack that can return the smallest element in the stack
Realize a special stack, and then realize the operation of returning the smallest element in the stack on the basis of realizing the basic functions of the stack.
requirement:
1. The time complexity of pop, push and getMin operations is O(1).
2. The designed stack type can use the ready-made stack structure.
Idea: use an additional stack to store the smallest elements.
package com.offer.class3; import java.util.Stack; /** * Maintain a minimum element with an additional stack space */ public class MyStack { private Stack<Integer> dataStack; private Stack<Integer> minStack; public MyStack(){ dataStack = new Stack<Integer>(); minStack = new Stack<Integer>(); } public void push(int obj){ dataStack.push(obj); if(minStack.isEmpty()){ minStack.push(obj); // When the minimum stack is empty, the number is saved directly }else if(obj <= minStack.peek()){ minStack.push(obj); // When obj is less than or equal to the minimum value in the minimum value stack, it is directly pushed into the stack }else{ minStack.push(minStack.peek()); // Press the minimum value in the minimum value stack again } } public int pop(){ minStack.pop(); return dataStack.pop(); } public int getMin(){ if(minStack.isEmpty()){ throw new ArrayIndexOutOfBoundsException("the stack is empty!"); } return minStack.peek(); } }
How to implement stack structure only with queue structure
Principle: two queues (queue and help) can be used to realize the stack. When adding elements, the addition is always in the queue; when deleting elements, all the elements before the last bit of the queue are ejected into the help queue, and then the last element returning to the queue is ejected (this meets the requirement of last in first out of the stack), and then the help and queue pointers can be exchanged
Queue: Poll (remove and return the head of the queue), add (add an element to the end of the queue), peek (return the head of the queue without deleting)
package com.offer.class3; import java.util.LinkedList; import java.util.Queue; /** * Queue with two stacks */ public class TwoQueueWithStack { private Queue<Integer> queue; private Queue<Integer> help; public TwoQueueWithStack(){ // LinkedList implements the Queue interface queue = new LinkedList<Integer>(); help = new LinkedList<Integer>(); } // Insert an element public void push(int obj){ // Insert elements are always inserted into the queue queue.add(obj); } // Delete an element public int pop(){ if(queue.isEmpty()){ throw new RuntimeException("stack is empty!"); } while(queue.size() > 1){ // Add all pop ups except the last element in the queue to help help.add(queue.poll()); } int res = queue.poll(); swap(); return res; } // Pop up an element (do not delete) public int peek(){ if(queue.isEmpty()){ throw new RuntimeException("stack is empty!"); } while(queue.size() > 1){ // Add all pop ups except the last element in the queue to help help.add(queue.poll()); } int res = queue.poll(); help.add(res); swap(); return res; } // Exchange the pointers of queue and help. Help is only an auxiliary queue and always operates on queue public void swap(){ Queue<Integer> temp = help; help = queue; queue = temp; } }
Fourth, how to implement queue structure only with stack structure?
Principle: two stacks (stack1 and stack2) can be used to realize the queue. When entering, it is put into stack1 stack and when leaving, it is out of stack2 stack. In this way, the order can be changed into FIFO (stack: push,pop,peek)
Points to note:
1. Only when stack2 is empty can stack1 put data into stack2, otherwise the order will be disordered;
2. If stack1 wants to put data into stack2, it must put all the data in stack1 into stack2 at one time.
package com.offer.class3; import java.util.Stack; /** * Queue with two stacks */ public class TwoStackWithQueue { Stack<Integer> stack1 = new Stack<Integer>(); Stack<Integer> stack2 = new Stack<Integer>(); // Add element public void add(int obj){ stack1.push(obj); } // Delete element public int poll(){ if(stack2.isEmpty() && stack1.isEmpty()){ throw new RuntimeException("queue is empty!"); }else if(stack2.isEmpty()){ while(!stack1.isEmpty()){ // If stack2 is empty, all the elements in stack1 will be poured into stack2 stack2.push(stack1.pop()); } } // If there is an element in stack2, it will pop up directly. Only when stack2 is empty, data will be put from stack1 to stack2, and it must be finished at one time return stack2.pop(); } // Pop up element, do not delete public int peek(){ if(stack2.isEmpty() && stack1.isEmpty()){ throw new RuntimeException("queue is empty!"); }else if(stack2.isEmpty()){ while(!stack1.isEmpty()){ // If stack2 is empty, all the elements in stack1 will be poured into stack2 stack2.push(stack1.pop()); } } // Pop up the top element in stack2, that is, the first in first out of the queue is realized return stack2.peek(); // The previous is the same as poll, but it needs to be returned instead of deleted } }
Five cats and dogs queue
The categories of pets, dogs and cats are as follows:
public class Pet { private String type; }
public Pet(String type) { this.type = type; }
public String getPetType() { return this.type; }
public class Dog extends Pet { public Dog() { super("dog"); } }
public class Cat extends Pet { public Cat() { super("cat"); } }
A dog cat queue structure is implemented, and the requirements are as follows:
The user can call the add method to put the instances of cat class or dog class into the queue;
You can call the pollAll method to pop up all instances in the queue in order of entering the queue;
The user can call the pollDog method to pop up the instances of the dog class in the queue in the order of entering the queue;
The user can call the pollCat method to pop up the instances of cat class in the queue according to the order of entering the queue;
The user can call isEmpty method to check whether there are still dog or cat instances in the queue;
The user can call the isDogEmpty method to check whether there is an instance of dog class in the queue;
The user can call the isCatEmpty method to check whether there is an instance of cat class in the queue.
analysis:
1. Create a cat and dog queue class, which contains DogQueue and CatQueue queues for adding cats and dogs respectively, but this will make it impossible to judge the order of cats and dogs in pollAll, so step 2 is provided;
2. Create a CatDog class, which contains pet and count members. Pet is used to record whether the instance of CatDog class is a cat or a dog. Count is used to record the order of the current pet. The smaller count is in the front, then the order of cats and dogs can be judged.
package com.offer.class3; import java.util.LinkedList; import java.util.Queue; /** * Cat dog queue problem */ public class CatDogQueue { public static class Pet{ private String type; public Pet(String type){ this.type = type; } public String getPetType(){ return this.type; } } public static class Dog extends Pet{ public Dog(){ super("dog"); } } public static class Cat extends Pet{ public Cat(){ super("cat"); } } public static class CatDog{ private Pet pet; // Used to record whether it is a cat or a dog private long count; // Used to record the order of the current pet public CatDog(Pet pet, long count){ this.pet = pet; this.count = count; } public Pet getPet(){ return this.pet; } public long getCount(){ return this.count; } } // Official code of CatDogQueue private Queue<CatDog> catQueue = new LinkedList<CatDog>(); // Cat queue private Queue<CatDog> dogQueue = new LinkedList<CatDog>(); // Dog queue private long count = 0; // Add element public void add(Pet pet){ if(pet.getPetType().equals("cat")){ catQueue.add(new CatDog(pet, count++)); }else if(pet.getPetType().equals("dog")){ dogQueue.add(new CatDog(pet, count++)); }else{ throw new RuntimeException("error : this is not cat or dog type!"); } } // Pop up all elements public Pet pollAll(){ if(!catQueue.isEmpty() && !dogQueue.isEmpty()){ if(catQueue.peek().count < dogQueue.peek().count){ // If the order of the first element of the cat queue is before the first element of the dog queue, the first element of the cat queue will pop up return catQueue.poll().getPet(); }else{ return dogQueue.poll().getPet(); } }else if(!catQueue.isEmpty()){ return catQueue.poll().getPet(); }else if(!dogQueue.isEmpty()){ return dogQueue.poll().getPet(); }else{ throw new RuntimeException("error : queue is empty!"); } } // Pop up dog cat column element public Cat pollCat(){ if(catQueue.isEmpty()){ throw new RuntimeException("error : the cat queue is empty!"); }else{ return (Cat) catQueue.poll().getPet(); } } // Pop up dog queue element public Dog pollDog(){ if(dogQueue.isEmpty()){ throw new RuntimeException("error : the dog queue is empty!"); }else{ return (Dog) dogQueue.poll().getPet(); } } public boolean isAllEmpty(){ return dogQueue.isEmpty() && catQueue.isEmpty(); } public boolean isDogQueueEmpty(){ return dogQueue.isEmpty(); } public boolean isCatQueueEmpty(){ return catQueue.isEmpty(); } }
On the issue of cat and dog queue, you can have a good experience of the design idea.