栈和队列
1.栈(Stack)
概念:栈是一种特殊的线性表,其只允许在固定的一端进行插入和删除元素操作。
进行数据插入和删除操作的一端称为栈 顶,另一端称为栈底。
栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。
压栈:栈的插入操作叫做进栈/压栈/入栈,入数据在栈顶。
出栈:栈的删除操作叫做出栈。出数据在栈顶
实现
- 利用顺序表实现,即使用尾插 + 尾删的方式实现
- 利用链表实现,则头尾皆可
- 相对来说,顺序表的实现上要更为简单一些,所以优先用顺序表实现栈。
基本操作
- 入栈 — — 插入数据(尾插)push()
- 出栈 — — 删除数据(尾删)pop()
- 查看栈顶元素 top()
- 返回栈内元素个数 size()
- 判断栈是否为空 isEmpty()
代码实现
import java.util.Arrays;
public class Stack
{
private int[] array;
private int top;
//扩容
public Stack(int defaultCapacity)
{
array = new int[defaultCapacity];
top = 0;
}
public Stack()
{
this(20);
}
//入栈
public void push(int val)
{
if (top == array.length)
{
array = Arrays.copyOf(array, array.length * 2);
}
array[top++] = val;
}
//出栈
public void pop()
{
if (top <= 0)
{
System.out.println("栈为空,无法删除");
return;
}
top--;
array[top] = 0; // 可加可不加,把所有空的位置保持为 0
}
//返回栈顶元素
public int top()
{
if (top <= 0)
{
System.out.println("栈为空,无法返回栈顶元素");
return -1;
}
return array[top - 1];
}
//返回栈内元素个数
public int size()
{
return top;
}
//判断栈是否为空
public boolean isEmpty()
{
return top == 0;
}
}
2.队列
概念:队列只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表。
队列具有先进先出FIFO(First In First Out) 的原则
入队列:进行插入操作的一端称为队尾(Tail/Rear)
出队列:进行删除操作的一端称为队头
实现
- 队列也可以数组和链表的结构实现。
- 使用链表的结构实现更优一些。
- 因为如果使用数组的结构,出队列在数组头上 出数据,效率会比较低.
代码实现
class Node
{
int val;
Node next;
Node(int val, Node next)
{
this.val = val;
this.next = next;
}
Node(int val)
{
this(val, null);
}
}
public class Queue
{
private Node front = null; // 链表的第一个结点
private Node rear = null; // 链表的最后一个结点
private int size = 0;
// 尾插
public void push(int val)
{
Node node = new Node(val);
if (front == null)
{
front = node;
}
else
{
rear.next = node;
}
rear = node;
size++;
}
// 头删
public void pop()
{
if (size <= 0)
{
System.out.println("队列为空");
return;
}
front = front.next;
if (front == null)
{
rear = null;
}
size--;
}
//返回队首元素
public int front()
{
if (size <= 0)
{
System.out.println("队列为空");
return -1;
}
return front.val;
}
//返回队尾元素
public int rear()
{
if (size <= 0)
{
System.out.println("队列为空");
return -1;
}
return rear.val;
}
//返回队内元素个数
public int size()
{
return size;
}
//判断队列是否为空
public boolean isEmpty()
{
return size == 0;
}
}
3.循环队列
1.数组下标循环的小技巧
- 下标最后再往后(offset 小于 array.length): index = (index + offset) % array.length
- 下标最前再往前(offset 小于 array.length): index = (index + array.length - offset) % array.length
2.如何区分空与满
- 通过添加 size 属性记录
- 保留一个位置
为了能使用Q.rear=Q.front来区别是对空还是队满,常认为左图是队满情况:此时rear+1=front;
代码实现
class MyCircularQueue
{
private int[] array;
private int size;
private int front;
private int rear;
//队列初始化
public MyCircularQueue(int k)
{
array = new int[k];
size = 0;
front = 0;
rear = 0;
}
//入队
public boolean enQueue(int value)
{
if (size == array.length)
{
return false;
}
array[rear] = value;
rear = (rear + 1) % array.length;
size++;
return true;
}
//出队
public boolean deQueue()
{
if (size == 0)
{
return false;
}
front = (front + 1) % array.length;
size--;
return true;
}
//获得队首元素
public int Front()
{
if (size == 0)
{
return -1;
}
return array[front];
}
//返回队尾元素
public int Rear()
{
if (size == 0)
{
return -1;
}
int index = (rear + array.length - 1) % array.length;
return array[index];
}
//判断循环队列是否为空
public boolean isEmpty()
{
return size == 0;
}
//判断是否队满
public boolean isFull()
{
return size == array.length;
}
}
4.Java中的栈和队列
Stack
Queue
Deque:双端队列
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列