Java实现栈和队列
一、什么是数据结构中的栈和队列
栈
(Stack):只允许在一端进行插入或删除的线性表。遵循后进先出原则(Last In First Out,简称LIFO)。栈顶
:允许插入删除元素的一侧栈底
:不插入删除元素的那一侧
队列
(Queue):只允许在一端进行插入操作,而在另一端进行删除操作的线性表。遵循先进先出原则(First In First Out,简称FIFO)。队头
:允许删除元素的一侧队尾
:允许插入元素的一侧
二、实现思路——链表
由于数组具有容量大小限制的缺点,用链表实现更加简单。
节点类Node
要想使用链表肯定要有节点类,这里我们使用泛型来约束节点存储值的类型
public class Node<E> {
E value; // 节点存储的值
Node<E> next; // 下一节点
public Node(E value) {
this.value = value;
next = null;
}
// 设置下一节点
public void setNext(Node<E> next){
this.next = next;
}
}
栈
栈的特点是只有一端有数据操作,所以我们只需要定义一个头节点即可,让头节点处进行数据的增删。
假设开始时栈是这样
插入元素后,很显然head要指向新节点,然后新节点要指向旧节点,我们的程序也这样写
public class MyStack<E> {
private Node<E> head; // 头结点
private int size; // 元素数量
// 构造函数,初始化头结点为空,长度为0
public MyStack(){
head = null;
size = 0;
}
// 入栈操作
public void push(E e) {
// 栈为空,初始化头结点为新元素
if(size == 0){
head = new Node<E>(e);
}else { // 栈不为空,head要指向新节点,新节点要指向旧节点
Node<E> oldNode = head.next;
Node<E> newNode = new Node<E>(e);
newNode.setNext(oldNode);
head.next = newNode;
}
size++;
}
// 出栈操作
public E pop() {
// 栈为空,抛出异常
if(size == 0){
throw new NullPointerException("栈中没有数据!");
}
// 取出头结点值并丢掉头结点
E e = head.value;
head = head.next;
size--;
return e;
}
// 查看元素数量
public int size(){
return size;
}
// 是否为空
public boolean isEmpty() {
return size == 0;
}
// 清空
public void clear() {
while (size > 0) {
this.pop();
}
}
}
队列
队列的特点是一端插入元素一端删除元素,那么我们定义两个节点:头结点(head)和尾节点(tail)
队列的思路很好想:尾端插入头部删除,
// 队列
public class MyQueue<E> {
// 头结点、尾结点、长度
private Node<E> head;
private Node<E> tail;
private int size;
// 构造函数,初始化头尾节点为空,长度为0
public MyQueue() {
head = tail = null;
size = 0;
}
// 插入元素:尾端插入
public void pull(E e) {
// 若插入前为空队列,则头尾节点都是该元素
if(size == 0){
head = tail = new Node<>(e);
}else { // 插入前不是空队列,尾部插入节点
tail.setNext(new Node<>(e));
tail = tail.next;
}
size++;
}
// 删除元素:头部删除
public E take() {
// 空队列直接抛出异常
if(size == 0){
throw new NullPointerException("队列为空!");
}
// 取出元素并抛弃头结点
E e = head.value;
head = head.next;
// 头结点为空证明队列中已经没有元素,因此尾结点也要为null
if(head == null){
tail = null;
}
size--;
return e;
}
// 返回长度
public int size() {
return size;
}
// 是否为空
public boolean isEmpty() {
return size == 0;
}
// 清空
public void clear() {
while (size > 0) {
this.take();
}
}
}