一.栈(Stack)
栈是一种后进先出 (LIFO, Last In First Out) 的数据结构。只允许在一端进行元素的删除或插入,也就是说,最后一个加入栈的元素最先被移除。这一端被称为栈顶(Top),另一端被称为栈底(Bottom)。
栈的基本操作包括:
压栈 (Push):将元素添加到栈的顶部。
弹栈 (Pop):移除并返回栈顶的元素。
查看栈顶元素 (Peek):返回栈顶的元素,但不移除它。
判断栈是否为空(IsEmpty):检查栈中是否有元素。
栈的实现通常使用数组或链表。数组实现的栈有固定大小,而链表实现的栈可以动态调整大小。
栈的Java数组实现
public class MyStackArr {
private int maxSize;//栈大小
private int[] stackArray;//栈
private int top;//栈顶
//栈的初始化 自定义栈的大小
public MyStackArr(int size) {
maxSize = size;
stackArray = new int[maxSize];
top = -1;
}
//压栈操作
public void push(int value) {
if (top == maxSize - 1) {
throw new RuntimeException("栈已满!");
}
stackArray[++top] = value;
}
//弹栈操作
public int pop() {
if (top == -1) {
throw new RuntimeException("栈为空!");
}
int value = stackArray[top];
stackArray[top--] = 0; // 将弹出的元素位置设置为0
return value;
}
//查看栈顶元素操作
public int peek() {
if (top == -1) {
throw new RuntimeException("栈为空!");
}
return stackArray[top];
}
//判断栈是否为空操作
public boolean isEmpty() {
return (top == -1);
}
//判断栈是否已满操作
public boolean isFull() {
return (top == maxSize - 1);
}
}
栈的Java链表实现:
private ListNode top;
public LinkedListStack() {
this.top = null;
}
public void push(int value) {
ListNode newNode = new ListNode(value);
newNode.next = top;
top = newNode;
}
public int pop() {
if (top == null) {
throw new RuntimeException("栈为空!");
}
int value = top.value;
top = top.next;
return value;
}
public int peek() {
if (top == null) {
throw new RuntimeException("栈为空!");
}
return top.value;
}
public boolean isEmpty() {
return top == null;
}
二.队列(Queue)
队列是一种先进先出(FIFO, First In First Out)的数据结构。双端操作,它允许在一端插入元素(称为队尾),在另一端删除元素(称为队头)。
队列的基本操作
初始化队列:创建一个空队列。
入队(Enqueue):将元素添加到队尾。
出队(Dequeue):从队头移除元素。
读队头元素(GetFront):获取队头元素但不删除。
判队空(QueueEmpty):判断队列是否为空
队列的实现通常使用数组、链表或循环数组。循环数组可以有效地利用空间,避免数组实现中的空间浪费问题。
队列的Java数组实现:
public class MyQueueArr {
private int maxSize; // 队列的最大容量
private int[] queueArray; // 用于存储队列元素的数组
private int front; // 队头指针
private int rear; // 队尾指针
private int nItems; // 队列中的元素数量
// 构造函数,初始化队列
public MyQueueArr(int size) {
maxSize = size; // 设置队列的最大容量
queueArray = new int[maxSize]; // 创建存储队列元素的数组
front = 0; // 初始化队头指针
rear = -1; // 初始化队尾指针
nItems = 0; // 初始化队列中的元素数量
}
// 入队操作,将元素添加到队尾
public void enqueue(int value) {
if (rear == maxSize - 1) { // 如果队尾指针到达数组末尾
rear = -1; // 将队尾指针重置为-1(循环队列)
}
queueArray[++rear] = value; // 将元素添加到队尾,并移动队尾指针
nItems++;
}
// 出队操作,从队头移除元素
public int dequeue() {
if (nItems == 0) {
throw new RuntimeException("队列为空!");
}
int temp = queueArray[front++];
if (front == maxSize) {
front = 0; // 将队头指针重置为0(循环队列)
}
nItems--;
return temp;
}
// 获取队头元素
public int peekFront() {
if (nItems == 0) {
throw new RuntimeException("队列为空!");
}
return queueArray[front]; // 返回队头元素
}
// 判断队列是否为空
public boolean isEmpty() {
return (nItems == 0);
}
// 判断队列是否已满
public boolean isFull() {
return (nItems == maxSize);
}
}
队列的Java链表实现
class ListNode {
int value;
ListNode next;
ListNode(int value) {
this.value = value;
this.next = null;
}
}
public class MyQueueLink {
private ListNode front;
private ListNode rear;
public MyQueueLink() {
this.front = null;
this.rear = null;
}
public void enqueue(int value) {
ListNode newNode = new ListNode(value);
if (rear == null) {
front = rear = newNode;
} else {
rear.next = newNode;
rear = newNode;
}
}
public int dequeue() {
if (front == null) {
throw new RuntimeException("队列为空!");
}
int value = front.value;
front = front.next;
if (front == null) {
rear = null;
}
return value;
}
public int peek() {
if (front == null) {
throw new RuntimeException("队列为空!");
}
return front.value;
}
public boolean isEmpty() {
return front == null;
}
}
三.栈和队列的转换
1.栈实现队列
使用两个栈来实现一个队列。一个栈用于存储新元素,另一个栈用于反转元素顺序以实现队列的先进先出特性。
思路
- 入队操作:将元素压入第一个栈。
- 出队操作:如果第二个栈为空,则将第一个栈中的所有元素弹出并压入第二个栈,然后从第二个栈弹出元素。
java代码实现:
public class MyQueueUsingMyStack {
private MyStack stackPush;
private MyStack stackPop;
public MyQueueUsingMyStack(int size) {
stackPush = new MyStack(size);
stackPop = new MyStack(size);
}
public void enqueue(int value) {
stackPush.push(value);
}
public int dequeue() {
if (stackPop.isEmpty()) {
while (!stackPush.isEmpty()) {
stackPop.push(stackPush.pop());
}
}
if (stackPop.isEmpty()) {
throw new RuntimeException("队列为空!");
}
return stackPop.pop();
}
public boolean isEmpty() {
return stackPush.isEmpty() && stackPop.isEmpty();
}
}
2.队列实现栈
我们将使用两个你自己设计的队列来实现一个栈。一个队列用于存储新元素,另一个队列用于辅助反转元素顺序以实现栈的后进先出特性。
思路
- 压栈操作:将元素添加到第一个队列。
- 弹栈操作:将第一个队列中的前n-1个元素移到第二个队列,最后一个元素即为栈顶元素,将其弹出。然后交换两个队列的角色。
java代码实现
public class MyStackUsingMyQueue {
private MyQueue queue;
private MyQueue helpQueue;
public MyStackUsingMyQueue(int size) {
queue = new MyQueue(size);
helpQueue = new MyQueue(size);
}
public void push(int value) {
queue.enqueue(value);
}
public int pop() {
if (queue.isEmpty()) {
throw new RuntimeException("栈为空!");
}
while (queue.size() > 1) {
helpQueue.enqueue(queue.dequeue());
}
int res = queue.dequeue();
MyQueue temp = queue;
queue = helpQueue;
helpQueue = temp;
return res;
}
public int peek() {
if (queue.isEmpty()) {
throw new RuntimeException("栈为空!");
}
while (queue.size() > 1) {
helpQueue.enqueue(queue.dequeue());
}
int res = queue.dequeue();
helpQueue.enqueue(res);
MyQueue temp = queue;
queue = helpQueue;
helpQueue = temp;
return res;
}
public boolean isEmpty() {
return queue.isEmpty();
}
}