栈(Stack)
概念
栈:一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。
进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。
栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶。
栈的使用
| 方法 |
功能 |
| Stack() |
构造一个空的栈 |
| E push(E e) |
将e入栈,并返回e |
| E pop() |
将栈顶元素出栈并返回 |
| E peek() |
获取栈顶元素 |
| int size() |
获取栈中有效元素个数 |
| boolean empty() |
检测栈是否为空 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
public static void main(String[] args) {
Stack<Integer> s = new Stack();
s.push(1);
s.push(2);
s.push(3);
s.push(4);
System.out.println(s.size()); // 获取栈中有效元素个数---> 4
System.out.println(s.peek()); // 获取栈顶元素---> 4
s.pop(); // 4出栈,栈中剩余1 2 3,栈顶元素为3
System.out.println(s.pop()); // 3出栈,栈中剩余1 2 栈顶元素为3
if(s.empty()){
System.out.println("栈空");
}else{
System.out.println(s.size());
}
}
|
栈的模拟实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
import java.util.Arrays;
public class MyStack {
int[] array;
int size;
public MyStack() {
array = new int[3];
}
public int push(int e) {
ensureCapacity();
array[size++] = e;
return e;
}
public int pop() {
int e = peek();
size--;
return e;
}
public int peek() {
if (empty()) {
throw new RuntimeException("栈为空,无法获取栈顶元素");
}
return array[size - 1];
}
public int size() {
return size;
}
public boolean empty() {
return 0 == size;
}
private void ensureCapacity() {
if (size == array.length) {
array = Arrays.copyOf(array, size * 2);
}
}
}
|
队列(Queue)
概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First
In First Out)
入队列:进行插入操作的一端称为队尾(Tail/Rear)
出队列:进行删除操作的一端称为队头 (Head/Front)
队列的使用
在Java中,Queue是个接口,底层是通过链表实现的。
| 方法 |
功能 |
boolean offer(E e) |
入队列 |
E poll() |
出队列 |
peek() |
获取队头元素 |
int size() |
获取队列中有效元素个数 |
boolean isEmpty() |
检测队列是否为空 |
注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口
队列模拟实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
public class Queue {
// 双向链表节点
public static class ListNode {
ListNode next;
ListNode prev;
int value;
ListNode(int value) {
this.value = value;
}
}
ListNode first; // 队头
ListNode last; // 队尾
int size = 0;
// 入队列---向双向链表尾部插入新节点
public void offer(int e) {
ListNode newNode = new ListNode(e);
if (first == null) { // 队列为空时
first = newNode;
} else { // 队列不为空时
last.next = newNode;
newNode.prev = last;
}
last = newNode;
size++;
}
// 出队列---将双向链表第一个节点删除掉
public Integer poll() {
// 1. 队列为空
if (first == null) {
return null;
}
int value = first.value; // 先保存要返回的值
// 2. 队列中只有一个元素
if (first == last) {
first = null;
last = null;
} else {
// 3. 队列中有多个元素
first = first.next;
first.prev.next = null; // 断开原队头节点的引用
first.prev = null;
}
size--;
return value;
}
// 获取队头元素---获取链表中第一个节点的值域
public Integer peek() {
if (first == null) {
return null;
}
return first.value;
}
public int size() {
return size;
}
public boolean isEmpty() {
return first == null;
}
}
|
循环队列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
public class CircularQueue {
private int[] arr; // 存储队列元素的数组
private int front; // 队头指针(指向队头元素)
private int rear; // 队尾指针(指向队尾元素的下一个位置)
private int capacity; // 队列的容量(实际可存储元素数量为capacity-1)
// 构造方法,初始化队列
public CircularQueue(int capacity) {
this.capacity = capacity;
arr = new int[capacity]; // 数组长度为capacity,但实际只能存capacity-1个元素
front = 0;
rear = 0;
}
// 入队操作
public boolean offer(int value) {
// 队列已满,入队失败
if (isFull()) {
return false;
}
arr[rear] = value;
rear = (rear + 1) % capacity; // 循环移动队尾指针
return true;
}
// 出队操作
public Integer poll() {
// 队列为空,出队失败
if (isEmpty()) {
return null;
}
int value = arr[front];
front = (front + 1) % capacity; // 循环移动队头指针
return value;
}
// 获取队头元素
public Integer peek() {
if (isEmpty()) {
return null;
}
return arr[front];
}
// 判断队列是否为空:队头和队尾指针指向同一位置
public boolean isEmpty() {
return front == rear;
}
// 判断队列是否已满:队尾指针的下一个位置是队头指针
public boolean isFull() {
return (rear + 1) % capacity == front;
}
// 获取队列中元素个数
public int size() {
// 计算元素数量:(队尾 - 队头 + 容量) % 容量
return (rear - front + capacity) % capacity;
}
}
|
双端队列 (Deque)
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。
那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
Deque是一个接口,使用时必须创建LinkedList的对象。
1
2
|
Deque<Integer> stack = new ArrayDeque<>();//双端队列的线性实现
Deque<Integer> queue = new LinkedList<>();//双端队列的链式实现
|