棧和隊列是兩種非常重要的數據結構,都是邏輯結構,也就是說,棧(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. 實現一個特殊的棧
實現一個特殊的棧,在實現棧的基本功能的基礎上,再實現返回棧中最小元素的操作。
【要求】
- pop、push、getMin操作的時間複雜度都是O(1)。
- 設計的棧類型可以使用現成的棧結構。
解題思路
定義兩個棧,一個棧用於存放所有數據,另一個輔助棧用來存放最小值,開始的時候,將第一個元素同時壓入兩個棧,之後,再壓入元素,第一個棧直接壓入,然後判斷這個元素是否比輔助棧中的棧頂元素小,小就壓入輔助棧,不小的話,就將輔助棧中的棧頂元素壓入。當彈出元素的時候,要同時彈出輔助棧中的棧頂元素。
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();
}
}
如有不足之處,歡迎指正,謝謝!