数据结构(八) — 栈的链式存储结构及实现

链栈的概念

上一节我们说了顺序栈,这节我们说链栈,那么什么是链栈呢?通常的理解是栈的链式存储结构,简称为链栈
在链栈中,栈顶放在单链表的头部。另外,都已经有了栈顶在头部了,单链表中比较常用的头结点也就失去了意义,通常对于链栈来说,是不需要头结点的。结构如图所示:
在这里插入图片描述
对于链栈来说,基本不存在栈满的情况,除非内存已经没有可以使用的空间,如果真的发生,那此时的计算机操作系统已经面临死机崩溃的情况,而不是这链栈是否溢出的问题。
但对于空栈来说,链表原定义是头指针指向空, 那么链栈的空其实就是 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)。对于空间性能, 顺序栈需要事先确定一个固定的长度,可能会存在内存空间浪费的问题,但它的优势是存取时定位很方便,而链栈则要求每个元素都有指针域,这同时也增加了一些内存开销,但对于栈的长度无限制。所以它们的区别和线性表中讨论的一样, 如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈会更好一些。

posted @ 2019-04-23 23:14  Z_WOLF  阅读(382)  评论(0编辑  收藏  举报