目录
1. 栈
1.1 概念
1.2 栈的种类
1.3 栈的实现
2. 队列
2.1 概念
2.2 队列实现
3. 循环队列
3.1 为什么会有循环队列
3.2 如何区分空与满
3.3 循环队列实现
栈是一种仅支持在表尾进行插入和删除操作的线性表,这一端被称为栈顶,另一端被称为栈底。元素入栈指的是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;元素出栈指的是从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。栈中的元素遵守后进先出(LIFO)的原则.
栈的底层实现有两种,基于数组的实现:顺序栈(ArrayList);基于链表的实现:链式栈(LinkedList)。
// 基于数组实现链表
public class Stack {
private E[] elementData; // 栈中的元素
private int size; // 当前栈中元素个数
public Stack() {
elementData = (E[]) new Object[10]; // 默认长度为10
}
public Stack(int initCap) {
elementData = (E[]) new Object[initCap]; // 初始长度
}
// 入栈
public void push(E value) {
// 扩容
if(size == elementData.length) {
int oldLength = elementData.length;
int newLength = oldLength << 1;
elementData = Arrays.copyOf(elementData, newLength);
}
// 在数组尾部添加元素
elementData[size++] = value;
}
// 出栈,返回原来的栈顶元素
public E pop () {
if(getSize() == 0) {
throw new NoSuchElementException("栈中没有元素!");
}
// 得到原来的栈顶元素位置
E oldVaule = elementData[size - 1];
size--;
elementData[size] = null;
return oldVaule;
}
// 查看栈顶元素
public E peek() {
if(getSize() == 0) {
throw new NoSuchElementException("栈中没有元素!");
}
return elementData[size - 1];
}
// 获取当前栈的长度
public int getSize() {
return size;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
for (int i = 0; i < size; i++) {
stringBuilder.append(elementData[i]);
if(i != size - 1) {
stringBuilder.append(",");
}
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}
队列是一种仅支持在表尾进行插入操作、在表头进行删除操作的线性表,插入端称为队尾,删除端称为队首,因整体类似排队的队伍而得名。它满足先进先出的性质(FIFO),元素入队即将新元素加在队列的尾,元素出队即将队首元素取出,它后一个作为新的队首。·
队列和栈相同也是可以使用数组和链表实现,但是对于队列来说使用链表的结构效率更高。
/**
* 基于链表的队列
*/
public class LinkedQueue{
private Node head;
private Node tail;
private int size;
private class Node {
private int data;
private Node next;
public Node(int data) {
this.data = data;
}
}
// 入队
public void offer(int value) {
Node node = new Node(value);
if(head == null) {
head = tail = node;
} else {
tail.next = node;
tail = node;
}
size++;
}
// 出队(队首元素出队)
public int poll() {
if(size == 0) {
throw new NoSuchElementException("对列为空!");
} else {
int oldValue = head.data;
Node tempHead = head;
head = head.next;
tempHead.next = null;
size--;
return oldValue;
}
}
// 查看队首元素
public int peek() {
if(size == 0) {
throw new NoSuchElementException("对列为空!");
}
return head.data;
}
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("front[");
Node node = head;
while (node != null) {
stringBuilder.append(node.data);
if(node.next != null) {
stringBuilder.append(",");
}
node = node.next;
}
stringBuilder.append("]tail");
return stringBuilder.toString();
}
}
在顺序队列中,当下标走到队尾后,不能再往后走插入元素,但其实数组中还有位置,这叫做“假溢出”,为了解决这个问题提高数组利用率,就出现了循环队列。
实现循环对列,最重要的是如何判断队列为空还是为满。
1. 通过 size 属性记录当前队列中的元素个数;
2. 保留一个位置,这个位置不能存储元素。这样当队满为 front == (rear+ 1)% length,队空为 front == rear。
front:指向循环队列的第一个元素下标,rear:指向循环队列的最后一个元素的下一个下标
/**
* 循环队列
*/
public class LoopQueue implements IQueue {
// 指向循环队列的最后一个元素的下一个位置
private int tail;
// 队首元素,指向队列中的第一个元素索引
private int front;
// 有效元素个数
private int size;
private int[] data;
public LoopQueue(int k) {
data = new int[k + 1];
}
// 判断队列是否已满
public boolean isFull() {
if ((tail + 1) % data.length == front) {
return true;
}
return false;
}
// 判断队列是否为空
public boolean isEmpty() {
// if (front == tail) {
// return true;
// }
// return false;
return tail == front;
}
// 入队
public void offer(int value) {
if (isFull()) {
System.err.println("队列已满!");
return;
} else {
data[tail] = value;
tail = (tail + 1) % data.length;
size++;
}
}
// 出队
public int poll() {
if (isEmpty()) {
System.err.println("队列为空!");
return -1;
} else {
int value = data[front];
front = (front + 1) % data.length;
size--;
return value;
}
}
// 查看队首元素
public int peek() {
if (isEmpty()) {
System.err.println("队列为空!");
return -1;
}
return data[front];
}
// 查看队尾元素
public int getTail() {
if (isEmpty()) {
System.err.println("队列为空!");
return -1;
}
// 最后一个元素的下标
int index = tail == 0 ? data.length - 1 : tail - 1;
return data[index];
}
// 判断有效个数
public int getSize() {
return size;
}
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
// 最后一个元素的位置
int lastIndex = tail == 0 ? data.length - 1 : tail - 1;
for (int i = front; i != tail; ) {
stringBuilder.append(data[i]);
if (i != lastIndex) {
stringBuilder.append(",");
}
i = (i + 1) % data.length;
}
stringBuilder.append("]");
return stringBuilder.toString();
}
}
活动地址:CSDN21天学习挑战赛