链栈的概念
上一节我们说了顺序栈,这节我们说链栈,那么什么是链栈呢?通常的理解是栈的链式存储结构,简称为链栈。
在链栈中,栈顶放在单链表的头部。另外,都已经有了栈顶在头部了,单链表中比较常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。结构如图所示:
对于链栈来说,基本不存在栈满的情况,除非内存已经没有可以使用的空间,如果真的发生,那此时的计算机操作系统已经面临死机崩溃的情况,而不是这链栈是否溢出的问题。
但对于空栈来说,链表原定义是头指针指向空, 那么链栈的空其实就是 top=NULL 的时候。
链栈的实现
以下是链栈的实现,代码如下:
public class LinkStack<T> {
private class Node {
private T data;// 保存节点的数据元素
private Node next;// 保存下一个节点的引用
public Node(T data, Node next) {
this.data = data;
this.next = next;
}
}
private Node top;// 存放栈顶节点
private int size = 0;// 存放栈中已有的元素个数
// 创建空链栈
public LinkStack() {
top = null;
}
// 已指定数据元素创建链栈,只有一个元素
public LinkStack(T element) {
top = new Node(element, null);
size++;
}
// 返回链栈的长度
public int length() {
return size;
}
// 进栈
public void push(T elemnt) {
// 让top指向新节点,新节点的next指向原来的top
top = new Node(elemnt, top);
size++;
}
// 出栈
public T pop() {
// 若当前为空栈,则返回null
if (size == 0) {
return null;
}
Node oldTop = top;
// 让top指向原栈顶的下一个节点
top = top.next;
// 释放原栈顶元素的引用
oldTop.next = null;
size--;
return oldTop.data;
}
// 获取栈顶元素
public T getTop() {
// 若当前为空栈,则返回null
if (size == 0) {
return null;
}
return top.data;
}
// 判断是否为空
public boolean isEmpty() {
return size == 0;
}
// 清空栈
public void clear() {
top = null;
size = 0;
}
}
顺序栈与链栈的对比
对比一下顺序栈与链栈,它们在时间复杂度上是一样的,均为O(1)。对于空间性能, 顺序栈需要事先确定一个固定的长度,可能会存在内存空间浪费的问题,但它的优势是存取时定位很方便,而链栈则要求每个元素都有指针域,这同时也增加了一些内存开销,但对于栈的长度无限制。所以它们的区别和线性表中讨论的一样, 如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。