栈
栈是线性表的一种,只允许在栈顶进行插入或者删除的一种数据结构,栈中的数据遵循先进后出或者说是后进先出的原则
- 出栈:对数据进行删除操作
- 入栈:对数据进行插入操作,入栈也叫做压栈
- 栈只有一个口,所以入栈出栈的操作都是在栈顶实现的
- 在 Java 集合中,栈是一个接口,可用顺序表和链表实现
- 在插入和删除数据时,我们可以认为是尾插/尾删操作,而对于顺序表来说,这种操作更容易实现,所以我们用顺序表来实现栈
import java.util.Arrays;
public class MyStack {
private int[] arr;
int size;
public MyStack(int defaultCapacity){
arr = new int[defaultCapacity];
size = 0;
}
public MyStack(){
this(20);
}
//插入操作
public void push(int element){
if(size==arr.length){//说明栈已经存储满
arr = Arrays.copyOf(arr,arr.length*2);//扩容
}
//为什么不是arr[++size] = element;
//我们这里用数组实现栈
//数组下标是从 0 开始存储的
arr[size++] = element;
}
//删除操作
public void pop(int element){
if(size<=0){
System.out.println("无法删除,栈为空");
return;
}
size--;
}
//返回栈顶元素
public int top(){
if(size<=0){
System.out.println("栈为空,无法返回栈顶元素");
return -1;
}
return arr[size-1];
}
//判断栈是否为空
public boolean isEmpty(){
return size==0;
}
//栈有多少元素
public int size(){
return size;
}
}
队列
队列只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出的特点
- 入队列:进行插入操作的一端称为队尾(Tail/Rear)
- 出队列:进行删除操作的一端称为队头(Head/Front)
队列也可以用顺序表和链表实现,如果用顺序表实现,进行删除操作时,需要将数组元素都进行移动,而链表直接让 head = head.next,相对来说,链表更容易实现,我们用链表模拟队列的实现
class Node{
int val;
Node next = null;
public Node(int val){
this.val = val;
}
}
public class MyQueue {
private Node front = null;
private Node rear = null;
int size = 0;
//队尾插入元素
public void offer(int val){
Node node = new Node(val);
if(rear==null){
front = node;
}else{
rear.next = node;
}
rear = node;
size++;
}
//队头删除元素
public void poll(){
if(size==0){
System.out.println("队列为空,无法删除");
return;
}
front = front.next;
if(front==null){
rear = null;
}
size--;
}
//返回队首元素
public int peek(){
if(size==0){
System.out.println("队列为空,无队首元素");
}
return front.val;
}
//判断队列是否为空
public boolean isEmpty(){
return size==0;
}
//队列有多少元素
public int size(){
return size;
}
}
循环队列
循环队列顾名思义就是队尾元素的下一个元素是队首元素,循环队列通常用数组实现
假如说要在队尾后面继续存放3个元素,那么最后一个元素的下标是多少?
i = (index + 3)%arr.length = (6+3)%7 = 2,所以在下标为 2 的位置上,通过观察,我们也确实发现在下标为 2 的位置上
如何区分队空和队满
队空:Q.rear==Q.front;
队满:(Q.rear + 1)%arr=front;
双端队列
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
Java 中的栈和队列
Stack
方法 | 解释 |
---|---|
E push (E item) | 压栈 |
E pop () | 出栈 |
E peek () | 获取栈顶元素 |
boolean empty () | 判断栈是否为空 |
import java.util.Stack;
public class StackDemo {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
stack.push("我");
stack.push("爱");
stack.push("小");
stack.push("年");
System.out.println(stack);
System.out.println(stack.empty());//false
System.out.println(stack.peek());//年
System.out.println(stack.pop());//年
System.out.println(stack.pop());//小
System.out.println(stack.pop());//爱
System.out.println(stack.pop());//我
System.out.println(stack.empty());//true
}
}
//执行结果
[我, 爱, 小, 年]
false
年
年
小
爱
我
true
Queue
方法 | 解释 |
---|---|
offer (e) | 入队列 |
poll () | 出队列 |
peek () | 获取队首元素 |
import java.util.LinkedList;
import java.util.Queue;
public class QueueDemo {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
queue.add("我");
queue.add("爱");
queue.offer("小");
queue.offer("年");
System.out.println(queue);
System.out.println(queue.isEmpty());//false
System.out.println(queue.poll());//我
System.out.println(queue.peek());//爱
System.out.println(queue.element());//爱
System.out.println(queue.remove());//爱
System.out.println(queue.remove());//小
System.out.println(queue.poll());//年
System.out.println(queue.isEmpty());//true
}
}
//执行结果
[我, 爱, 小, 年]
false
我
爱
爱
爱
小
年
true