zoukankan      html  css  js  c++  java
  • Java容器&数据结构——栈

      “栈”通常指“后进先出”的(LIFO)容器。本文将分别介绍基于LinkedList和不依赖LinkedList的两种实现方法。

      友情提示:这里,我假设读者已经了解泛型,内部类,LinkedList容器以及递归的概念,如果没有,可能会对您的理解造成一点不便。

    一、基于LinkedList的实现

      在Java中,LinkedList具有能够实现栈的所有功能的方法,因此可以将LinkedList作为栈使用,实现类可以非常的优雅而简洁:

    package com.test.collection;
    
    import java.util.LinkedList;
    
    public class Stack<T> {
        private LinkedList<T> storage = new LinkedList<T>();
        public void push(T v) {
            storage.addFirst(v);
        }
        public T peek() {
            return storage.getFirst();
        }
        public T pop() {
            return storage.removeFirst();
        }
        public boolean empty() {
            return storage.isEmpty();
        }
        public String toString() {
            return storage.toString();
        }
    }
    View Code

      通过使用泛型,引入了栈在类定义中最简单的可行示例。push()接受T类型对象并压入栈中,而peek()和pop()将返回T类型的对象。区别是前者仅返回栈顶元素,后者返回并移除栈顶元素。

      如果你只需要栈的行为,这里使用继承就不合适了,因为这样会产生具有LinkedList其他所有方法的类(据说,Java1.0设计者在设计Java.util.Stack时,就犯了这个错误)。因此尽管已经有了java.util.Stack,但是LinkedList可以产生更好的Stack,下面的测试类中同时测试自己实现的Stack和Java.util.Stack里的Stack

    package com.test.collection;
    
    public class StackCollision {
    
        public static void main(String[] args) {
            com.test.collection.Stack<String> stack = new com.test.collection.Stack<String>();
            for(String s : "My dog has fleats".split(" "))
                stack.push(s);
            while(!stack.empty())
                System.out.print(stack.pop() + " ");
            System.out.println();
            java.util.Stack<String> stack2 = new java.util.Stack<String>();
            for(String s : "My dog has fleats".split(" "))
                stack2.push(s);
            while(!stack2.empty())
                System.out.print(stack2.pop() + " ");
        }
    
    }
    View Code

    测试结果:

    这里创建Stack实例时,需要完整地指定包名,否则有可能与java.util包中的Stack产生冲突。这两个Stack具有相同的接口,但是java.util中没有任何公共的Srack接口。

    二、不依赖于LinkedList的实现

      如上面的例子所示,LinkedList本身已经具备了创建堆栈所必须的方法。我们只需要将LinkedList已有的方法进行封装,就可以完成一个堆栈的实现了。但是如果我觉得这样不利于我深入理解堆栈的实现,不想调用LinkedList的方法,想自己从头实现,该怎么办呢?下面的例子或许可以给你提供一点思路:

     1 package com.test.generic;
     2 
     3 public class LinkedStack<T> {
     4     private class Node<U> {
     5         U item;
     6         Node<U> next;
     7         Node() {
     8             item = null;
     9             next = null;
    10         }
    11         Node(U item, Node<U> next) {
    12             this.item = item;
    13             this.next = next;
    14         }
    15         boolean end() {
    16             return item == null && next == null;
    17         }
    18     }
    19     private Node<T> top = new Node<T>();//End sentiel 末端哨兵
    20     public void push(T item) {
    21         top = new Node<T>(item, top);
    22     }
    23     public T pop() {
    24         T result = top.item;
    25         //item和next(节点参数)任意一个非null,则查找下一个节点,若item和next
    26         //的值均为null,则不再查找下一个节点,直接返回null的result = top.item
    27         if(!top.end())
    28             top = top.next;
    29         return result;
    30     }
    31     
    32     public static void main(String[] args) {
    33         LinkedStack<String> lss = new LinkedStack<String>();
    34         for(String s : "Phasers on stun!".split(" "))
    35             lss.push(s);
    36         String s;
    37         while((s = lss.pop()) != null)
    38             System.out.println(s);
    39     }
    40 }
    View Code

      上例使用了一个带泛型参数的内部类Node<U>作为堆栈节点,参数item为泛型,用于接收节点上各种类型的对象或者基本类型;类型为next作为节点参数,接收下一个节点的信息;top为末端哨兵(end sential)的一个例子,与前两个参数配合,实现判断堆栈何时为空。这个末端哨兵实在构造LinkedStack时创建的,然后,每调用一次push()方法,就会创建一个Node<T>对象。调用pop()方法时,总是返回top.item,然后舍弃当前top所指的Node<T>,并将top转移到下一个Node<T>,碰到末端哨兵,就不在移动top,因为如果到了末端,再继续调用pop方法,只能得到null,说明堆栈已经空了。

      输出结果中我们可以看到,被顺序装入的字符串"Phasers","on","stun!"被倒序的输出,符合堆栈“后进先出”(LIFO)的特性。

      最后,感谢Bruce Eckel提供的例子。

  • 相关阅读:
    JS 保存表单默认值 为空时自动填充默认值
    .net 防盗链
    Subversion安装和使用
    (转) MFC的入口点与消息循环,消息映射
    ASP.NET树形控件TreeView的递归绑定
    SQL Server中的分页
    C# 调用WebService的方法
    从零开始定义自己的JavaScript框架(一)
    JS中的call和apply
    JS中的自执行函数
  • 原文地址:https://www.cnblogs.com/junqiao/p/6490030.html
Copyright © 2011-2022 走看看