栈和队列都是特殊的线性表,它们的插入和删除操作都是事先规定好的。
第一节 栈
1 定义
栈(Stack):只允许在一端进行插入和删除操作的线性表。
栈顶(Top):允许进行插入和删除的那一端。
栈底(Bottom):不允许进行插入和删除的那一端。
其操作的特性是后进先出(Last In First Out, LIFO)。
2 顺序栈
采用顺序存储的栈称为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时设一个指针(top)指示当前栈顶的位置。
public class MyArrayStack<T> { private T[] data; // 存放元素的数组 private int top = -1; // 栈顶,初始值为-1 private int maxSize; // 栈容量 /** * 初始化栈 * @param maxSize */ public MyArrayStack(int maxSize) { this.maxSize = maxSize; data = (T[]) new Object[this.maxSize]; } /** * 判栈空 * @return */ public boolean isEmpty() { return top == -1; } /** * 判栈满 * @return */ public boolean isFull() { return top == this.maxSize - 1; } /** * 入栈 * @param data * @return */ public boolean push(T data) { if (this.isFull()) { throw new RuntimeException("栈满"); } this.data[++this.top] = data; return true; } /** * 出栈 * @return */ public T pop() { if (this.isEmpty()) { throw new RuntimeException("栈空"); } return this.data[this.top--]; } /** * 查看栈顶元素 * @return */ public T peek() { if (this.isEmpty()) { throw new RuntimeException("栈空"); } return this.data[this.top]; } }
3 链栈
采用链式存储的栈称为链栈。
链栈的优点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。
通常采用单链表实现,并规定所有操作都是在单链表的表头进行的。
public class MyLinkedStack<T> { private Node<T> head; // 栈头 private int length; // 栈长度 /** * 初始化 */ public MyLinkedStack() { this.head = new Node<>(); this.length = 0; } /** * 判栈空 * @return */ public boolean isEmpty() { return this.head == null; } /** * 获取栈长度 * @return */ public int size() { return this.length; } /** * 进栈 * @param data * @return */ public boolean push(T data) { Node<T> node = new Node<>(data); boolean flag = false; if (this.isEmpty()) { this.head.next = node; this.length++; flag = true; } else { node.next = this.head.next; this.head.next = node; this.length++; flag = true; } return flag; } /** * 出栈 * @return */ public T pop() { T data = null; if (this.isEmpty()) { throw new RuntimeException("栈空"); } else if (this.length == 1) { data = (T) this.head.next.data; this.head.next = null; } else { data = (T) this.head.next.data; this.head.next = this.head.next.next; } return data; } /** * 查看栈顶元素 * @return */ public T peek() { T data = null; if (this.isEmpty()) { throw new RuntimeException("栈空"); } else { data = (T) this.head.next.data; } return data; } public void print() { if (this.isEmpty()) { System.out.println("栈空"); } else { Node<T> cur = this.head; while (cur.next != null) { cur = cur.next; System.out.println(cur.data); } } } /** * 栈元素 * @param <T> */ private class Node<T> { private T data; private Node next; public Node() { } public Node(T data) { this.data = data; } } public static void main(String[] args) { MyLinkedStack<String> list = new MyLinkedStack<>(); list.push("a"); list.push("b"); list.push("c"); list.print(); System.out.println("========"); System.out.println(list.pop()); System.out.println("======="); list.print(); } }
第二节 队列
1 定义
队列(Queue)也是一种操作受限的线性表,它只允许在表的一端进行插入,而在表的另一端进行删除。
向队列中插入元素称为入队;删除元素称为出队。其操作的特性是先进先出(First In First Out, FIFO)。
队头(Front):允许删除的一端。
队尾(Rear):允许插入的一端。
2 顺序存储的队列
队列的顺序实现是指分配一块连续的存储单元存放队列中的元素,并附设两个指针front和rear分别指示队列头元素和队尾元素的位置。将数组想象成一个环状的空间,可以充分利用数组的空间,称之为循环队列。
public class MyArrayQueue<T> { private T[] arr; // 存放元素的数组 private int front; // 队头索引 private int rear; // 队尾索引 private int maxSize; // 队列容量 private int length; // 队长 /** * 初始化队列 * @param maxSize */ public MyArrayQueue(int maxSize) { this.maxSize = maxSize; this.arr = (T[]) new Object[this.maxSize]; // 初始化数组 this.front = -1; // 初始化队头索引 this.rear = -1; // 初始化队尾索引 this.length = 0; // 初始化队长 } /** * 判队空 * @return */ public boolean isEmpty() { return this.length == 0; } /** * 判队满 * @return */ public boolean isFull() { return this.length == this.maxSize; } /** * 入队 * @param data * @return */ public boolean enQueue(T data) { if (this.isFull()) { throw new RuntimeException("队满"); } boolean flag = false; if (isEmpty()) { arr[this.rear + 1] = data; this.rear = (this.rear + 1) % this.maxSize; this.front = (this.front + 1) % this.maxSize; this.length++; flag = true; } else { arr[this.rear + 1] = data; this.rear = (this.rear + 1) % this.maxSize; this.length++; flag = true; } return flag; } /** * 出队 * @return */ public T deQueue() { if (this.isEmpty()) { throw new RuntimeException("队空"); } T data = arr[this.front]; this.front = (this.front + 1) % this.maxSize; this.length--; return data; } public void print() { if (this.isEmpty()) { System.out.println("队空"); } else { if (this.front < this.rear) { for (int i = this.front; i <= this.rear; i++) { System.out.println(arr[i]); } } else { for (int i = this.front; i < this.maxSize; i++) { System.out.println(arr[i]); } for (int i = 0; i <= this.rear; i++) { System.out.println(arr[i]); } } } } public static void main(String[] args) { MyArrayQueue<String> queue = new MyArrayQueue<>(10); queue.print(); queue.enQueue("a"); queue.enQueue("b"); queue.enQueue("c"); queue.enQueue("d"); System.out.println("==========="); queue.print(); System.out.println("==========="); System.out.println("出队:"+queue.deQueue()); queue.print(); System.out.println("==========="); System.out.println("出队:"+queue.deQueue()); queue.print(); } }