栈和队列的数据结构的实现过程(Java 实现)
栈的数据结构的实现
栈的基础知识回顾
栈是一种线性结构。
相比数组,栈对应的操作是数组的子集。
也就是栈可基于数组实现,可以将栈看成一种特殊的数组。
栈只能从一端添加元素,也只能从一端取出元素,这一端称为栈顶。
栈是一种 后进先出 (LIFO: Last In First Out) 的数据结构。
栈的常见应用
撤销(Undo)操作
程序调用的系统栈
基于数组的栈的实现
对于栈这种数据结构,实现起来是十分简单的,这里实现以下几个操作:
入栈:void push(E element)
出栈: E pop()
查看栈顶元素: E peek()
获取栈中元素个数: int getSize()
判断栈是否为空: boolean: isEmpty()
对于代码的具体实现,可以让其支持多态性。所以可以设计一个接口 Stack 定义上面这 5 个栈支持的操作,再设计一个类 ArrayStack 来实现这个接口。
对于 ArrayStack 这个类,实质上是基于之前实现的动态数组类 Array 来实现的一个数组栈。因为对于栈而言,栈对应的操作是数组的子集。可以把栈当成一个数组来看待。
对于 Array 类的具体实现过程,可查看另一篇 文章 。
具体代码设计
在编写栈的具体代码之前,先往工程中导入之前实现的动态数组类 Array,该类代码可从之前的文章中查阅, 因为要基于该类来实现数组栈。
ArrayStack 类的实现:
因为在 Array 类中已经实现了很多操作数组的方法。所以对于 ArrayStack 类实现接口中的方法时,只需复用 Array 类中的方法即可。
基于 Array 类实现 ArrayStack 类也有一些好处:
和 Array 一样拥有了动态伸缩容量的功能,我们不需要关心栈的容量是否够用,因为容量会动态地进行扩大和缩小。
对于一些非法变量的判断直接复用了 Array 类中的代码,不需要重复编写。
同时,也可以为 ArrayStack 类添加一个接口中没有的方法 getCapacity 提供给用户获取栈的容量。这个方法是这个类中特有的。
在实现 peek 方法之前,可以在 Array 类中扩展两个新方法用于获取数组末尾和数组首部的元素,方便在 ArrayStack 类和后续队列的实现中直接复用。
/**
* 获取数组的最后一个元素
*
* @return 返回数组的最后一个元素
*/
public E getLast() {
return get(size - 1);
}
/**
* 获取数组的第一个元素
*
* @return 返回数组的第一个元素
*/
public E getFirst() {
return get(0);
}
Stack 接口类代码如下:
/**
* 定义栈的基本操作的接口
* 支持泛型
*
* @author 踏雪寻梅
* @date 2020/1/8 - 19:20
*/
public interface Stack {
/**
* 获取栈中元素个数
*
* @return 栈中如果有元素,返回栈中当前元素个数;栈中如果没有元素返回 0
*/
int getSize();
/**
* 判断栈是否为空
*
* @return 栈为空,返回 true;栈不为空,返回 false
*/
boolean isEmpty();
/**
* 入栈
* 将元素 element 压入栈顶
*
* @param element 入栈的元素
*/
void push(E element);
/**
* 出栈
* 将当前栈顶元素出栈并返回
*
* @return 返回当前出栈的栈顶元素
*/
E pop();
/**
* 查看当前栈顶元素
*
* @return 返回当前的栈顶元素
*/
E peek();
}
ArrayStack 类代码实现如下:
/**
* 基于之前实现的动态数组类 Array 实现的数组栈类 ArrayStack
* 同样支持泛型
*
* @author 踏雪寻梅
* @date 2020/1/8 - 19:26
*/
public class ArrayStack implements Stack {
/**
* 动态数组 array
* 基于 array 实现栈的操作
*/
private Array array;
/**
* 构造函数
* 创建一个容量为 capacity 的数组栈
*
* @param capacity 要创建的栈的容量,由用户指定
*/
public ArrayStack(int capacity) {
array = new Array<>(capacity);
}
/**
* 默认构造函数
* 创建一个默认容量的数组栈
*/
public ArrayStack() {
array = new Array<>();
}
@Override
public int getSize() {
// 复用 array 的 getSize() 方法即可
return array.getSize();
}
@Override
public boolean isEmpty() {
// 复用 array 的 isEmpty() 方法即可
return array.isEmpty();
}
/**
* 获取栈的容量
* ArrayStack 特有的方法
*
* @return 返回栈的容量
*/
public int getCapacity() {
// 复用 array 的 getCapacity() 方法即可
return array.getCapacity();
}
@Override
public void push(E element) {
// 将数组的末尾作为栈顶,复用 array 的 addLast() 方法实现
array.addLast(element);
}
@Override
public E pop() {
// 将数组的末尾作为栈顶,复用 array 的 removeLast() 方法将栈顶元素出栈并返回
return array.removeLast();
}
@Override
public E peek() {
// 将数组的末尾作为栈顶,复用 array 的 getLast() 方法获取栈顶元素
return array.getLast();
}
/**
* 重写 toString 方法返回数组栈的信息
*
* @return 返回数组栈的当前信息
*/
@Override
public String toString() {
StringBuilder result = new StringBuilder();
result.append("ArrayStack: ");
result.append("size: ").append(array.getSize()).append(" ");
result.append("capacity: ").append(array.getCapacity()).append(" ");
result.append("bottom -> [ ");
for (int i = 0; i < array.getSize(); i++) {
result.append(array.get(i));
// 如果不是最后一个元素
if (i != array.getSize() - 1) {
result.append(", ");
}
<