1.栈(Stack)
1.1 概念
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈 顶,另一端称为栈底。栈中的数据元素遵守
后进先出
(
Last In First Out
)的原则。
压栈:栈的插入操作叫做进栈
/
压栈
/
入栈,
入数据在栈顶
。
出栈:栈的删除操作叫做出栈。
出数据在栈顶
。
1.2 实现
1.利用链表实现,头尾皆可.
2.利用顺序表实现,即使用尾插+尾删的方式
优先考虑用顺序表实现栈!
public class MyStack {
int[] elem ;
int usedSize;
public MyStack() {
this.elem = new int [10];
}
public void push(int val) {
if (isFull()) {
//扩容
this.elem = Arrays.copyOf(elem,12*elem.length) ;
}
elem[usedSize] = val;
usedSize++;
}
public boolean isFull() {
return usedSize == elem.length;
}
public int pop() {
if (isEmpty()) {
// throw new EmptyException("栈是空的!");
return -1;
}
usedSize--;
return elem[usedSize];
}
public boolean isEmpty() {
return usedSize == 0;
}
public int peek() {
if (isEmpty()) {
//throw new EmptyException("栈是空的!");
return -1;
}
return elem[usedSize - 1];
}
}
2.队列(Queue)
2.1 概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出
FIFO(First
In First Out)
入队列:进行插入操作的一端称为
队尾(
Tail/Rear
)
出队列:进行删除操作的一端称为
队头
2.2 实现
队列可以用数组或着链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队列在数组头上出数据,效率会比较低。
演示下单链表实现队列,代码如下:双链表实现队列才是最优,无论从哪里入和出都是O(1).
public class MyQueue {
/*
* 单链表实现队列
*/
static class Node {
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
}
public Node head;
public Node last;
public int usedSize;
//入队
public void offer(int val) {
Node node = new Node(val);
if (head == null) {
head = node;
last = node;
}else {
last.next = node;
last = node;
}
usedSize++;
}
//出队
public int poll() {
if (isEmpty()) {
//throw new EmptyException("栈为空!");
return -1;
}
int ret = head.val;
head = head.next;
if (head == null) {
last = null; //删除的只有一个节点,last也要置空
}
usedSize--;
return ret;
}
public int peek() {
if (isEmpty()) {
//throw new EmptyException("栈为空!");
return -1;
}
return head.val;
}
public boolean isEmpty() {
return usedSize == 0;
}
}
2.3 循环队列
操作系统课程讲解生产者消费者模型时可以就会使用循环队列。循环队列通常使用数组实现。
如果用普通数组实现就会出现这种情况,不能是普通数组,要用循环数组,所以就引出了循环队列!
循环数组:
数组下标循环的小技巧!
1.
下标最后再往后
(offset
小于
array.length): index = (index + offset) % array.length
2.
下标最前再往前
(offset
小于
array.length): index = (index + array.length - offset) % array.length
如何区分空与满
1.
通过添加
usedSize
属性记录
2.
保留一个位置(通常牺牲一个空间)
3.双端队列(Deque)
3.1 概念
双端队列(
deque
)是指允许两端都可以进行入队和出队操作的队列,
那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
//链式实现双端对列 底层是双向链表
Deque<Integer> deque = new LinkedList<>();
//线式实现双端对列 底层是数组
Deque<Integer> deque1 = new ArrayDeque<>();
尽管双端队列看起来似乎比栈和队列更灵活,但实际上在 应用程序中远不及 栈和队列有用。