队列和栈的问题
一、用数组结构实现大小固定的栈
【核心思想】
栈结构是“后进先出”,有初始化栈、入栈、出栈、返回栈顶等功能,题目大意就是要求我们用数组实现栈的这些功能。
初始化栈:给定一个初始大小,创建一个栈。定义一个变量 size ,初始化为 0,用来记录栈中的元素数量。
入栈:如果 size 小于栈的大小,将要入栈的数放入数组的 size 位置上,size 加 1。否则报错。
出栈:如果 size 大于 0,返回数组( size - 1 ) 位置上的数,size 减 1。否则报错。
返回栈顶:如果 size 大于 0,返回数组(size - 1)位置上的数。否则报错。
【代码实现】
public class ArrayToStack { private int[] arr; private int size; /** * 初始化栈 * @param initSize */ public ArrayToStack(int initSize) { if (initSize < 0) { throw new IllegalArgumentException("The init size is less than 0!"); } arr = new int[initSize]; size = 0; } /** * 入栈 * @param obj */ public void push(int obj) { //size等于数组长度(栈的大小),说明栈已满,不能入栈 if (size == arr.length) { throw new IndexOutOfBoundsException("The stack is full!"); } arr[size++] = obj; } /** * 出栈 * @return */ public int pop() { //size等于0,说明栈空,不能出栈。 if (size == 0) { throw new IndexOutOfBoundsException("The stack is empty!"); } return arr[--size]; } /** * 返回栈顶第一个元素 * @return */ public int peek() { //size等于0,说明栈空,所以没有栈顶。 if (size == 0) { throw new IndexOutOfBoundsException("The stack is empty!"); } return arr[size - 1]; } }
二、用数组结构实现大小固定的队列
【核心思想】
【实现代码】
public class ArrayToQueue { private Integer[] arr; private Integer size; private Integer start; private Integer end; /** * 初始化队列 * @param initSize */ public ArrayToQueue(int initSize) { if (initSize < 0) { throw new IllegalArgumentException("The init size is less than 0"); } arr = new Integer[initSize]; size = 0; start = 0; end = 0; } /** * 入队 * @param obj */ public void push(int obj) { if (size == arr.length) { throw new ArrayIndexOutOfBoundsException("The queue is full"); } size++; arr[end] = obj; end = end == arr.length - 1 ? 0 : end + 1; } /** * 出队 * @return */ public Integer pop() { 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]; } /** * 返回队列的第一个数 * @return */ public Integer peek() { if (size == 0) { return null; } //如果size不等于0,返回start指向的数 return arr[start]; } }
三、如何仅用队列结构实现栈结构?
【实现思路】
【代码实现】
/** * 仅用队列结构实现栈结构 * * @author yi */ public class QueueToStack { private Queue<Integer> data; private Queue<Integer> help; public QueueToStack() { this.data = new LinkedList<Integer>(); this.help = new LinkedList<Integer>(); } /** * 正常push添加进入queue * @param value */ public void push(int value) { data.add(value); } /** * 在pop的时候,pop只留下一个元素,并把pop出来的元素加入到help队列中 * @return */ public int pop() { if (data.isEmpty()) { throw new RuntimeException("栈为空"); } while (data.size() > 1) { //把data中的元素"剪切"到help队列,直到data只剩下一个元素 help.add(data.poll()); } //最后一个入队的元素 int res = data.poll(); //交换help和data的引用指向 swap(); return res; } /** * 返回栈顶的第一个元素 * @return */ public int peek() { if (data.isEmpty()) { throw new RuntimeException("栈为空"); } while (data.size() > 1) { help.add(data.poll()); } int res = data.poll(); help.add(res); swap(); return res; } public void swap() { Queue<Integer> temp = help; help = data; data = temp; } }
四、如何仅用栈结构实现队列结构?
【实现思路】
【代码实现】
/** * 仅用栈结构实现队列结构 * * @author yi */ public class StackToQueue { private Stack<Integer> stackPush; private Stack<Integer> stackPop; public StackToQueue() { stackPush = new Stack<>(); stackPop = new Stack<>(); } /** * 入队 * @param obj */ public void push(int obj) { stackPush.push(obj); } /** * 出队 * @return */ public int poll() { if (stackPop.empty() && stackPush.empty()) { throw new RuntimeException("Queue is empty!"); } else if (stackPop.empty()) { while (!stackPush.empty()) { stackPop.push(stackPush.pop()); } } return stackPop.pop(); } /** * 返回队列的第一个数 * @return */ public int peek() { if (stackPop.empty() && stackPush.empty()) { throw new RuntimeException("Queue is empty!"); } else if (stackPop.empty()) { while (!stackPush.empty()) { stackPop.push(stackPush.pop()); } } return stackPop.peek(); } }
五、栈的补充练习
实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。
【要求】
1.pop、push、getMin操作的时间复杂度都是O(1)。
2.设计的栈类型可以使用现成的栈结构。
【实现思路】
【代码实现】
public class MyStack { private Stack<Integer> stackData; private Stack<Integer> stackMin; public MyStack() { this.stackData = new Stack<>(); this.stackMin = new Stack<>(); } public void push(int newNum) { if (this.stackMin.isEmpty()) { this.stackMin.push(newNum); } else if (newNum < this.getMin()) { this.stackMin.push(newNum); } else { int newMin = this.stackMin.peek(); this.stackMin.push(newMin); } this.stackData.push(newNum); } public int pop() { if (this.stackData.isEmpty()) { throw new RuntimeException("Your stack is empty"); } this.stackMin.pop(); return this.stackData.pop(); } public int getMin() { if (this.stackMin.isEmpty()) { throw new RuntimeException("Your stack is empty."); } return this.stackMin.peek(); } public static void main(String[] args) { MyStack stack = new MyStack(); stack.push(3); System.out.println(stack.getMin());//3 stack.push(5); System.out.println(stack.getMin());//3 stack.push(1); System.out.println(stack.getMin());//1 System.out.println(stack.pop());//1 System.out.println(stack.getMin());//3 } }
六、队列的补充练习
6.1 猫狗队列问题
【题目】
宠物、狗和猫的类如下:
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"); } }
【要求】
实现一种狗猫队列的结构,要求如下:
- 用户可以调用add方法将cat类或dog类的 实例放入队列中;
- 用户可以调用pollAll方法,将队列中所有的实例按照进队列 的先后顺序依次弹出;
- 用户可以调用pollDog方法,将队列中dog类的实例按照 进队列的先后顺序依次弹出;
- 用户可以调用pollCat方法,将队列中cat类的实 例按照进队列的先后顺序依次弹出;
- 用户可以调用isEmpty方法,检查队列中是 否还有dog或cat的实例;
- 用户可以调用isDogEmpty方法,检查队列中是否有dog 类的实例; 用户可以调用isCatEmpty方法,检查队列中是否有cat类的实例
【代码实现】
public class DogCatQueue_Code { /** * 以下的Pet、Dog、Cat类是用户提供的基础类,不能修改 */ 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"); } } /** * 为了不修改原来的基础类,我们自定义一个PetEnterQueue类,这个类才是放入到猫狗队列中去的对象 * 保留原来的属性pet,并且新增一个count属性,将不同实例盖上时间戳 */ 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 this.pet; } public long getCount() { return this.count; } public String getEnterPetType() { return this.pet.getPetType(); } } /** * 我们实现的队列就是PetEnterQueue类的实例 * 首先有一个不断累加的数据项count用来表示实例进队列的时间(不分cat还是dog) * 同时有两个队列,一个只存放Dog,另一个只存放Cat。 */ public static class DogCatQueue { private Queue<PetEnterQueue> dogQ; private Queue<PetEnterQueue> catQ; private long count; public DogCatQueue() { this.dogQ = new LinkedList<>(); this.catQ = new LinkedList<>(); this.count = 0; } public void add(Pet pet) { //如果pet是dog类型 if (pet.getPetType().equals("dog")) { //在dog队列中添加信息:当前进入的是dog,并且当前数是count this.dogQ.add(new PetEnterQueue(pet, this.count++)); } else if (pet.getPetType().equals("cat")) { this.catQ.add(new PetEnterQueue(pet, this.count++)); } else { throw new RuntimeException("err, not dog or cat"); } } /** * 弹出整体最早的 * @return */ public Pet pollAll() { if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()) { //dog队列最早的dog最小,还是cat队列最早的cat最小 //注意这里使用的是peek而不是poll //peek用于查询队列头部的元素;poll用于弹出队列中的头部元素 if (this.dogQ.peek().getCount() < this.catQ.peek().getCount()) { return this.dogQ.poll().getPet(); } else { return this.catQ.poll().getPet(); } } else if (!this.dogQ.isEmpty()) { return this.dogQ.poll().getPet(); } else if (!this.catQ.isEmpty()) { return this.catQ.poll().getPet(); } else { throw new RuntimeException("err, queue is empty!"); } } /** * 单独弹出dog * @return */ public Dog pollDog() { if (!this.isDogQueueEmpty()) { return (Dog) this.dogQ.poll().getPet(); } else { throw new RuntimeException("Dog queue is empty!"); } } /** * 单独弹出cat * @return */ public Cat pollCat() { if (!this.isCatQueueEmpty()) { return (Cat) this.catQ.poll().getPet(); } else { throw new RuntimeException("Cat queue is empty!"); } } public boolean isDogQueueEmpty() { return this.dogQ.isEmpty(); } public boolean isCatQueueEmpty() { return this.catQ.isEmpty(); } } public static void main(String[] args) { DogCatQueue test = new DogCatQueue(); Pet dog1 = new Dog(); Pet cat1 = new Cat(); Pet dog2 = new Dog(); Pet cat2 = new Cat(); Pet dog3 = new Dog(); Pet cat3 = new Cat(); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); test.add(dog1); test.add(cat1); test.add(dog2); test.add(cat2); test.add(dog3); test.add(cat3); while (!test.isDogQueueEmpty()) { System.out.println(test.pollDog().getPetType()); } while (!test.isCatQueueEmpty()) { System.out.println(test.pollCat().getPetType()); } } }