文章目录
- 一、栈
- 1、使用
- 2、应用场景
- 3、模拟实现
- 二、队列
- 1、使用
- 2、模拟实现
- 3、循环队列
- 4、双端队列
- 4.1 模拟实现双端队列
一、栈
栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out) 的原则。
- 入栈: 栈的插入操作称为进栈\入栈\压栈,入栈的元素保存在栈顶。
- 出栈: 栈的删除操作称为出栈。出栈元素是栈顶元素。
1、使用
方法 | 作用 |
| 构造一个空的栈 |
| 将e入栈,并返回e |
| 将栈顶元素出栈并返回 |
| 获取栈顶元素 |
| 获取栈中有效元素个数 |
| 检测栈是否为空 |
public static void method1() {
//Stack测试
Stack<Integer> s = new Stack<>();
s.push(1);
s.push(2);
s.push(3);
s.push(4);
System.out.println("s = " + s);
System.out.println("s.pop() = " + s.pop());
System.out.println("s = " + s);
System.out.println("s.peek() = " + s.peek());
if(s.empty())
System.out.println("empty");
else
System.out.println("元素个数为:"+s.size());
}
public static void main(String[] args) {
method1();
}
2、应用场景
- 改变元素的序列
- 将递归转化为循环
- 括号匹配
- 逆波兰表达式求值
3、模拟实现
Stack继承了Vector,Vector与ArrayList类似,都是动态顺序表。
public class MyStack<E> {
E[] array;
int size;
public MyStack(){
array = (E[]) new Object[3];
}
//入栈
public E push(E e){
ensureCapacity();
array[size++] = e;
return e;
}
//出栈
public E pop(){
E e = peek();
size--;
return e;
}
//取栈顶元素
public E peek(){
if (empty()){
throw new RuntimeException("栈为空");
}
return array[size--];
}
//判断栈是否为空
public boolean empty(){
return 0 == size;
}
//容量不够扩容
public void ensureCapacity(){
if(size == array.length)
array = Arrays.copyOf(array,size*2);
}
}
队列是一种只允许在其一端进行插入数据操作,在其另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out)
- 入队列: 进行插入操作的一端称为队尾(Tail/Rear)
- 出队列: 进行删除操作的一端称为队头(Head/Front)
1、使用
方法 | 作用 |
| 入队列 |
| 出队列 |
| 获取队头元素 |
| 获取队列中有效元素个数 |
Queue
是个接口,在实例化时必须实例化LinkedList
的对象,因为LinkedList
实现了Queue
接口。
public static void method2(){
//Queue测试
Queue<Integer> q = new LinkedList<>();
q.offer(1);
q.offer(2);
q.offer(3);
q.offer(4);
System.out.println("q = " + q);
q.add(5);
q.add(6);
System.out.println("q = " + q);
System.out.println("q.size() = " + q.size());
System.out.println("q.peek() = " + q.peek());
System.out.println("q.poll() = " + q.poll());
System.out.println("q = " + q);
if (q.isEmpty())
System.out.println("为空");
else
System.out.println("元素个数为:"+q.size());
}
public static void main(String[] args) {
method2();
}
2、模拟实现
Java中Queue
public class MyQueue<E> {
public static class Node<E>{
private E value;
private Node<E> next;
public Node(E val){
value = val;
next = null;
}
}
Node<E> front;
Node<E> back;
int size;
//入队列
public boolean offer(E e){
Node<E> node = new Node<>(e);
if (null == front){
front = node;
}else{
back.next = node;
}
back = node;
size++;
return true;
}
//出队列
public E poll(){
if (0 == size)
throw new RuntimeException("队列为空");
Node<E> delNode = front;
front = front.next;
if(null == front){
back = null;
}
size--;
return delNode.value;
}
//取队头元素
public E peek(){
if (0 == size)
throw new RuntimeException("队列为空");
return front.value;
}
public boolean isEmpty(){
return 0 == size;
}
public int size(){
return size;
}
}
3、循环队列
两种方式实现下标的循环:
- 下标最后再往后(offset 小于 array.length): index = (index + offset) % array.length。
- 下标最前再往前(offset 小于 array.length): index = (index + array.length - offset) % array.length
区分循环队列的空与满
- 使用size添加记录。
- 预留一个位置用做判断。
- 使用标记判断。
图2便是利用预留一个位置的方式来对循环队列是否满做判断,认为此时图2的情况便是循环队列满,即:队尾+1=队首
4、双端队列
双端队列(deque)是允许两端都可以进行入队或出队操作的队列,说明元素可以从队头出队和入队,也可以从队尾出队和入队。
4.1 模拟实现双端队列
力扣中也有该题:设计循环双端队列
//使用数组实现较为简单
class MyCircularDeque {
private int[] elements;
private int size;
public MyCircularDeque(int k) {
elements = new int[k];
}
public boolean insertFront(int value) {
if(isFull())
return false;
for(int i = size-1;i >= 0; i--){
elements[i+1] = elements[i];
}
elements[0] = value;
size++;
return true;
}
public boolean insertLast(int value) {
if(isFull())
return false;
elements[size] = value;
size++;
return true;
}
public boolean deleteFront() {
if(isEmpty())
return false;
for(int i = 1; i < size; i++){
elements[i-1] = elements[i];
}
size--;
return true;
}
public boolean deleteLast() {
if(isEmpty())
return false;
elements[size-1] = -1;
size--;
return true;
}
public int getFront() {
if(0 == size)
return -1;
return elements[0];
}
public int getRear() {
if(0 == size)
return -1;
return elements[size-1];
}
public boolean isEmpty() {
if(0 == size)
return true;
return false;
}
public boolean isFull() {
if(elements.length == size)
return true;
return false;
}
}