算法笔记——左神初级(4)数组生成栈与队列结构、栈队列相互转换

固定数组生成栈

栈:先入后出
这里设置的是固定长度的栈,而不是变长的栈;
除了准备size以外,还应有个index指示,该指示标志的是新来的数放置的位置。

public class Code_01_Array_To_Stack_Queue {

	public static class ArrayStack {
		private Integer[] arr;
		private Integer index;

//新建数据时,需要确定数组开多大
		public ArrayStack(int initSize) {  
			if (initSize < 0) {
				throw new IllegalArgumentException("The init size is less than 0");
			}
			arr = new Integer[initSize];
			index = 0;
		}

		public Integer peek() {
			if (index == 0) {
				return null;
			}
			return arr[index - 1];
		}

		public void push(int obj) {
			if (index == arr.length) {  //判断满了没
				throw new ArrayIndexOutOfBoundsException("The queue is full");
			}
			arr[index++] = obj;
		}

		public Integer pop() {
			if (index == 0) {
				throw new ArrayIndexOutOfBoundsException("The queue is empty");
			}
			return arr[--index];
		}
	}

固定数组生成队列

类似于fifo
先入先出
size 约束first和last指针
数组是循环利用的,判断空满只需要判断size的值即可

public static class ArrayQueue {
		private Integer[] arr;
		private Integer size;
		private Integer first;
		private Integer last;

		public ArrayQueue(int initSize) {
			if (initSize < 0) {
				throw new IllegalArgumentException("The init size is less than 0");
			}
			arr = new Integer[initSize];
			size = 0;    //一开始都指向0
			first = 0;
			last = 0;
		}

		public Integer peek() {  //返回第一个值
			if (size == 0) {
				return null;
			}
			return arr[first];
		}

		public void push(int obj) {   //入栈操作 如果栈满就丢异常
			if (size == arr.length) {
				throw new ArrayIndexOutOfBoundsException("The queue is full");
			}
			size++;  //否则size++
			arr[last] = obj;
			//如果last已经到底,就会回到0位置,循环利用 只要size没超就行
			last = last == arr.length - 1 ? 0 : last + 1;  
		}

		public Integer poll() {
			if (size == 0) {
				throw new ArrayIndexOutOfBoundsException("The queue is empty");
			}
			size--;
			int tmp = first;
			first = first == arr.length - 1 ? 0 : first + 1;
			return arr[tmp];
		}
	}

题目二:实现一个特殊的栈,返回最小元素

在实现栈的基本功能的基础上,再实现返 回栈中最小元素的操作。
【要求】
1.pop、push、getMin操作的时间复杂度都是O(1)。
2.设计的栈类型可以使用现成的栈结构。

设计思路:设计两个栈

这里主要是要求getMin的时间复杂度为O(1),所以考虑牺牲额外空间复杂度

  1. 一个data栈、一个min栈
  2. data压入一个数,min栈同时压入一个数。如果data数比min栈的栈顶数小,min栈压入data的数;如果min栈顶数小,则再压入一个栈顶数。
  3. 如果弹出,则两个栈都同时弹出。

代码如下:

public static class MyStack2 {
		private Stack<Integer> stackData;  
		private Stack<Integer> stackMin;

		public MyStack2() {
			this.stackData = new Stack<Integer>();
			this.stackMin = new Stack<Integer>();
		}

		public void push(int newNum) {  //压栈操作
			if (this.stackMin.isEmpty()) {   //这几个判断都是判断min栈放入什么数
				this.stackMin.push(newNum);
			} else if (newNum < this.getmin()) { //如果data栈的数小于min栈顶,则压入data栈的数
				this.stackMin.push(newNum);
			} else {
				int newMin = this.stackMin.peek(); //min栈顶再压一次
				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();
		}
	}

题目3:仅用队列结构实现栈结构与仅用栈结构实现队列结构

一、两个队列实现栈结构:

  1. 首先数据先进入队列1,然后除最后一个数外,其余进入队列2
  2. 把队列1中的数输出
  3. 除队列2中最后一个数外,其余出队列进入队列1
  4. 把队列2中的数输出
  5. 反复

例如:5、4、3、2、1----5+4321----321+4-----3+21

public static class TwoQueuesStack {
		private Queue<Integer> data;  //数据进入的队列
		private Queue<Integer> help;  //数据输出的队列

		public TwoQueuesStack() {
			data = new LinkedList<Integer>();
			help = new LinkedList<Integer>();
		}

		public void push(int pushInt) {
			data.add(pushInt);     //所有的输入数据只存放在当前的进入队列中
		}

		public int peek() { //查看栈顶的数
			if (data.isEmpty()) {
				throw new RuntimeException("Stack is empty!");
			}
			while (data.size() != 1) {  //这一步和下面的pop意义一样
				help.add(data.poll());
			}
			int res = data.poll();
			help.add(res);   //区别在这里,返回的结果也会重新放到help中去,不会弹出
			swap();
			return res;
		}

		public int pop() {  //弹出
			if (data.isEmpty()) {
				throw new RuntimeException("Stack is empty!");
			}
			while (data.size() > 1) {  //除了最后一个数,data队列中的所有数输入到help队列里
				help.add(data.poll());
			}
			int res = data.poll(); //直到最后一个数输出
			swap();  //交换两个队列的索引
			return res;
		}

		private void swap() {
			Queue<Integer> tmp = help;
			help = data;
			data = tmp;
		}

	}

二、两个栈实现队列结构:

  1. 一个pop栈、一个push栈;数据都进入push栈里;
  2. 需要开始出队列的时候,将push栈里的所有数都倒入pop栈中,然后pop栈出栈即可
  3. 如果再输入数据,则还是压入push栈里
  4. 注意,倒数据的前提是pop栈为空,否则顺序出错。

代码如下: 好理解

public static class TwoStacksQueue {
		private Stack<Integer> stackPush;
		private Stack<Integer> stackPop;

		public TwoStacksQueue() {
			stackPush = new Stack<Integer>();
			stackPop = new Stack<Integer>();
		}

		public void push(int pushInt) {
			stackPush.push(pushInt);
		}

		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(); //之前的判断和循环主要是为了确保pop栈里的正确
		}

		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();
		}
	}

题目4:猫狗队列问题

算法笔记——左神初级(4)数组生成栈与队列结构、栈队列相互转换_第1张图片
思路:

  1. 准备两个队列
  2. 猫进猫队列,狗进狗队列,同时给猫和狗打上时间戳
  3. 值得注意的是应该新建一个类,这个类包含Pet类以及一个时间戳变量,这个类就是下面的PetEnterQueue
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 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();
		}
	}

	public static class DogCatQueue {
		private Queue<PetEnterQueue> dogQ;
		private Queue<PetEnterQueue> catQ;
		private long count;

		public DogCatQueue() {
			this.dogQ = new LinkedList<PetEnterQueue>();
			this.catQ = new LinkedList<PetEnterQueue>();
			this.count = 0;
		}

		public void add(Pet pet) {
			if (pet.getPetType().equals("dog")) {
				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");
			}
		}

		public Pet pollAll() {
			if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()) {
				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!");
			}
		}

		public Dog pollDog() {
			if (!this.isDogQueueEmpty()) {
				return (Dog) this.dogQ.poll().getPet();
			} else {
				throw new RuntimeException("Dog queue is empty!");
			}
		}

		public Cat pollCat() {
			if (!this.isCatQueueEmpty()) {
				return (Cat) this.catQ.poll().getPet();
			} else
				throw new RuntimeException("Cat queue is empty!");
		}

		public boolean isEmpty() {
			return this.dogQ.isEmpty() && this.catQ.isEmpty();
		}

		public boolean isDogQueueEmpty() {
			return this.dogQ.isEmpty();
		}

		public boolean isCatQueueEmpty() {
			return this.catQ.isEmpty();
		}

	}

可以重点留意下取出的判断条件,别的较简单

你可能感兴趣的:(算法笔记,队列,算法,数据结构)