一、逻辑概念
1、栈:数据先进后出,犹如弹匣
2、队列:数据先进先出,好似排队
二、栈和队列的实现
1、双向链表实现
java
package class02;
/**
* 双向链表-实现栈和队列
*/
public class Code03_DoubleEndsQueueToStackAndQueue {
// 双向链表的节点类型
public static class Node<T> {
public T value;
public Node<T> last;
public Node<T> next;
public Node(T data) {
value = data;
}
}
// 实现双向链表
public static class DoubleEndsQueue<T> {
public Node<T> head;
public Node<T> tail;
// 从头部加节点
public void addFromHead(T value) {
Node<T> cur = new Node<T>(value);
if (head == null) {
head = cur;
tail = cur;
} else {
cur.next = head;
head.last = cur;
head = cur;
}
}
// 从尾部加节点
public void addFromBottom(T value) {
Node<T> cur = new Node<T>(value);
if (head == null) {
head = cur;
tail = cur;
} else {
tail.next = cur;
cur.last = tail;
tail = cur;
}
}
// 从头部获取节点
public T popFromHead() {
if (head == null) {
return null;
}
Node<T> cur = head;
if (head == tail) {
head = null;
tail = null;
} else {
head = head.next;
cur.next = null;
head.last = null;
}
return cur.value;
}
// 从尾部获取节点
public T popFromBottom() {
if (head == null) {
return null;
}
Node<T> cur = tail;
if (head == tail) {
head = null;
tail = null;
} else {
tail = tail.next;
tail.next = null;
cur.next = null;
}
return cur.value;
}
// 判断是否为空
public boolean isEmpty() {
return head == null;
}
}
// 实现栈
public static class MyStack<T> {
private DoubleEndsQueue<T> queue;
public MyStack() {
queue = new DoubleEndsQueue<T>();
}
// 从头部进
public void push(T value) {
queue.addFromHead(value);
}
// 从头部出
public T pop() {
return queue.popFromHead();
}
public boolean isEmpty() {
return queue.isEmpty();
}
}
// 实现队列
public static class MyQueue<T> {
private DoubleEndsQueue<T> queue;
public MyQueue() {
queue = new DoubleEndsQueue<T>();
}
// 从头部进
public void push(T value) {
queue.addFromHead(value);
}
// 从尾部出
public T poll() {
return queue.popFromBottom();
}
public boolean isEmpty() {
return queue.isEmpty();
}
}
public static boolean isEqual(Integer o1, Integer o2) {
if (o1 == null && o2 != null) {
return false;
}
if (o1 != null && o2 == null) {
return false;
}
if (o1 == null && o2 == null) {
return true;
}
return o1.equals(o2);
}
}
2、数组实现(固定大小)
java
package class02;
/**
* 环形数组-实现栈
*/
public class Code04_RingArray {
public static class MyStack {
private int[] arr;
private int pushi;
private int polli;
private int size;
private final int limit;
public MyStack(int limit) {
arr = new int[limit];
pushi = 0;
polli = 0;
size = 0;
this.limit = limit; // 最大的大小
}
// 加元素
public void push(int value) {
if (size == limit) {
throw new RuntimeException("栈满了,不能再加了");
}
size++;
arr[pushi] = value;
pushi = nextIndex(pushi);
}
// 减元素
public int pop() {
if (size == 0) {
throw new RuntimeException("栈空了,不能再拿了");
}
size--;
int ans = arr[polli]; //从poll index给出答案
polli = nextIndex(polli); //poll index来到下一个位置
return ans;
}
public boolean isEmpty() {
return size == 0;
}
// 如果现在的下标是i,返回下一个位置
private int nextIndex(int i) {
return i < limit - 1 ? i + 1 : 0;
}
}
}
队列:要有一个机制循环使用数组
putindex、size、limit
三、既然语言都有这些结构和api,为什么还需要手撸练习
1、算法问题无关语言
2、语言提供的api是有限的,当有新的功能是api不提供的,就需要改写
3、任何软件工具的底层都是最基本的算法和数据结构,这是绕不过去的
四、栈和队列常见面试题
1、怎么用数组实现不超过固定大小的队列和栈?
栈:正常使用
队列:环形数组
2、实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能
1)pop、push、getMin操作的时间复杂度都是O(1)
维护一个min成员变量行不行,不行,你知道当前最小的,返回后,剩余元素中最小的不知道
解决办法:
维护两个栈,一个data栈,一个min栈
push的时候:当前加的数,和最小数栈的栈顶谁小加谁
pop的时候:同步弹出
getMin:最小数栈的栈顶
2)设计的栈类型可以使用现成的栈结构
java
package class02;
import java.util.Stack;
/**
* 实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能
*/
public class Code05_getMinStack {
public static class MyStack1 {
private Stack<Integer> stackData;
private Stack<Integer> stackMin;
public MyStack1() {
this.stackData = new Stack<Integer>();
this.stackMin = new Stack<Integer>();
}
public void push(int newNum) {
if (this.stackMin.isEmpty()) {
this.stackMin.push(newNum);
} else if (newNum <= this.getMin()) {
this.stackMin.push(newNum);
} else {
this.stackMin.push(this.getMin());
}
this.stackData.push(newNum);
}
public int pop() {
if (this.stackData.isEmpty()) {
throw new RuntimeException("栈是空的");
}
this.stackMin.pop();
return this.stackData.pop();
}
public int getMin() {
if (this.stackMin.isEmpty()) {
throw new RuntimeException("栈是空的");
}
return this.stackMin.peek();
}
}
}
3、如何用栈结构实现队列结构
1)用两个栈,一个push栈,一个pop栈
2)入队列12345
3)弹出时把54321移动到pop栈,push栈一定要导空
4)弹出1
5)再把2345导回push栈
4、如何用队列结构实现栈结构
1)用两个队列,一个data队列,一个help队列
2)入栈12345
3)出栈时把1234移动到help队列
4)5出栈
5)颠倒两个队列,help变成data队列,data变成help队列