文章目录
一、基本含义
参考:https://mp.weixin.qq.com/s/D9_wM42c3Czhg9-NsPFJ8Q
链表和数组是线性结构的基础,栈和队列是线性结构的应用。
1.1 栈
含义:可以将栈看成一个箱子。
作用:放置数据。
分类:静态栈(数组实现) + 动态栈(链表实现)。
项目 | 含义 |
---|---|
入栈 | 往箱子里面放东西 |
出栈 | 往箱子里面取东西 |
栈底 | 箱子的底部 |
栈顶 | 箱子的顶部 |
特性 | 先进后出(LIFO, Last In First Out) |
1.2 队列
含义:可以将队列看成小朋友排队。
作用:放置数据。
分类:静态队列(数组实现) + 动态队列(链表实现)。
项目 | 含义 |
---|---|
入队 | 新的小朋友排队打饭了 |
出队 | 小朋友打完饭,走了。 |
队头 | 第一个小朋友 |
对尾 | 最后一个小朋友 |
特性 | 先进先出 |
二、代码实现
2.1 栈
2.1.1 创建节点类与栈类
本处采用链表创建动态栈。
Node.java
public class Node {
public int data;//数据域
public Node next;//指针域,指向下一个节点
public Node() {
}
public Node(int data) {
this.data = data;
}
public Node(int data, Node next) {
this.data = data;
this.next = next;
}
}
Stack.java
public class Stack {
public Node stackTop; // 栈顶指针
public Node stackBottom; // 栈底指针
public Stack(Node stackTop, Node stackBottom) {
this.stackTop = stackTop;
this.stackBottom = stackBottom;
}
public Stack() {
}
}
2.1.2 遍历栈
含义:获取节点值。
只要栈顶元素的指针不指向栈底,那么就一直输出遍历结果。
public static void traverse(Stack stack) {
Node stackTop = stack.stackTop;
while (stackTop != stack.stackBottom) {
System.out.println("栈元素值:" + stackTop.data);
stackTop = stackTop.next;
}
}
2.1.3 判断该栈是否为空
含义:是否有元素。
只要栈顶和栈底是同一指向,那么该栈就为空。
public static boolean isEmpty(Stack stack) {
return ((stack.stackTop == stack.stackBottom) ? true:false);
}
2.1.4 入栈(进栈)
含义:增加新节点。
将原本栈顶指向的节点交由新节点来指向,栈顶指向新加入的节点。
public static void pushStack(Stack stack, int value) {
Node newNode = new Node(value); // 新节点
// 交换。
newNode.next = stack.stackTop;// 栈顶本来指向的节点交由新节点来指向
stack.stackTop = newNode;// 栈顶指针指向新节点
}
2.1.5 出栈
含义:删除元素。
1、在出栈之前看看该栈是否为空,不为空才出栈…
2、将栈顶的元素的指针(指向下一个节点)赋值给栈顶指针(完成出栈)
public static void popStack(Stack stack) {
// 栈不为空才能出栈
if (!isEmpty(stack)) {
Node top = stack.stackTop;//栈顶元素
stack.stackTop = top.next; // 栈顶指针指向下一个节点
System.out.println("出栈的元素是:" + top.data);
}
}
2.1.6 清空栈
含义:删除所有元素。
栈顶指向栈底,就清空栈了。
public static void clearStack(Stack stack) {
stack.stackTop = null; // 栈顶置空
stack.stackBottom = stack.stackTop; // 栈底指向栈顶。
}
2.2 队列
使用数组来实现静态队列,往往实现静态队列,我们都是做成循环队列。
做成循环队列的好处是不浪费内存资源!
注意:
1、初始值,front = 0,rear = 0;
2、非循环队列时:入队时,rear++。出队时,front++。
3、数组长度 >= 队列长度 + 1
4、循环队列时:入队时,(rear+1)% arr.length。出队时,(front + 1) % arr.length。
2.2.1 创建队列类
Queue.java
public class Queue {
public int [] arrays; // 数组
public int front; // 指向第一个有效的元素
public int rear; // 指向有效数据的下一个元素(即指向无效的数据)
}
// rear并不指向最后一个有效的元素。目的:让我们分得清队头和队尾。
2.2.2 初始化队列
此时队列为空,分配了6个长度给数组(只能装5个实际的数字,rear指向的是无效的位置的)
public static void main(String[] args) {
//初始化队列
Queue queue = new Queue();
queue.front = 0;
queue.rear = 0;
queue.arrays = new int[6];
}
// 注意:此处数组长度虽然为6,但只能装5个实际数字。
// 注意:一般情况下,队列的长度 != 数组的长度。满员时,队列的长度 + 1 = 数组的长度。原因rear指向的是无效的位置的。
2.2.3 遍历
只要front节点不指向rear节点,那么就可以一直输出
public static void traverseQueue(Queue queue) {
int i = queue.front;// front的位置
while (i != queue.rear) {
System.out.println("元素的值" + queue.arrays[i]);
i = (i + 1) % queue.arrays.length;//移动front
}
}
2.2.4 判断
队列满员状态:如果rear指针和front指针紧挨着,那么说明队列就满了。
队列为空状态:只要rear和front指针指向同一个位置,那该队列就是空的了
// 队列是否满了。
public static boolean isFull(Queue queue) {
boolean result = ((queue.rear + 1) % queue.arrays.length == queue.front)? true:false;
return result;
}
// 队列是否为空
public static boolean isEmpty(Queue queue) {
return (queue.rear == queue.front) ? true:false;
}
2.2.4 入队
1、判断该队列是否满了。
2、入队的值插入到队尾中(具体的位置就是rear指针的位置)。
3、rear指针移动,再次指向无效的元素位置。
public static void enQueue(Queue queue,int value) {
// 不是满的队列才能入队
if (!isFull(queue)) {
// 将新的元素插入到队尾中
queue.arrays[queue.rear] = value;
// rear节点移动到新的无效元素位置上
queue.rear = (queue.rear + 1) % queue.arrays.length;
}
}
2.2.6 出队
1、判断该队列是否为null
2、如果不为null,则出队,只要front指针往后面移就是出队了!
public static void outQueue(Queue queue) {
if (!isEmpty(queue)) {
int value = queue.arrays[queue.front];
System.out.println("出队的元素是:" + value);
// front指针往后面移
queue.front = (queue.front + 1) % queue.arrays.length;
}
}