按链表的组织形式分有ArrayList和LinkList两种。ArrayList内部其实是用数组的形式实现链表,比较适合链表大小确定或较少对链表进行增删操作的情况,同时对每个链表节点的访问时间都是constant;而LinkList内部以一个List实现链表,比较适合需要频繁对链表进行操作的情况,对链表节点的访问时间与链表长度有关O(N)。
    另外,根据实现形式可以分为直接式(想不出什么合适的名字,姑且这样吧)和使用Iterator(迭代模式)两种方法。直接式的实现方法和C/C++中的写法差不多;而使用Iterator时,需要实现java.lan中的Iterable接口(或者也可以自己在链表内部定义自己的Iterator method)

使用迭代模式的优点:
           1,实现功能分离,简化容器接口。让容器只实现本身的基本功能,把迭代功能委让给外部类实现,符合类的设计原则。
           2,隐藏容器的实现细节。
           3,为容器或其子容器提供了一个统一接口,一方面方便调用;另一方面使得调用者不必关注迭代器的实现细节。
           4,可以为容器或其子容器实现不同的迭代方法或多个迭代方法。
    我觉得第4点说的很好,对于一堆数据而言,不同的人(或业务逻辑)使用它的方式也不尽相同,定义一个theIterator继承Iterator,不仅提供next,hasNext 以及remove这个最小的操作集合,同时也可以提供更多的其它方法。在theIterator的实现类中,具体实现不同的迭代方法,比如顺序、逆序或根据其它语义进行遍历等,再通过类厂的方式将一个theIterator实现的对象交给用户使用。
下面我给出两个例子:
    首先是直接式实现链表的例子,这个例子只提供了几种链表操作的基本方法,仅用于示意:

  1. public class MyList<AnyType>  {
  2. private class Node<AnyType>{
  3. public  Node<AnyType> pre;
  4. public  Node<AnyType> next;
  5. public  AnyType      data;
  6. public Node(AnyType d, Node<AnyType>p, Node<AnyType> n){}
  7. public Node(){}
  8. }
  9. private int theSize;
  10. private Node<AnyType> Header;
  11. private Node<AnyType> Tail;
  12. public MyList(){}
  13. public void add(AnyType item){}
  14. public boolean isEmpty(){}
  15. public int size(){}
  16. public AnyType get( int idx){}
  17. public void print(){}
  18. }
Node<AnyType>类定义了双向链表中节点的结构,它是一个私有类,而其属性和构造函数都是公有的,这样,其父类可以直接访问其属性,而外部类根本不知道Node类的存在。Data是节点中的数据与,pre指向前一个Node节点,next指向后一个Node节点。其构造函数的实现如下,不解释:
  1. public Node(AnyType d, Node<AnyType>p, Node<AnyType> n){
  2. this.data = d;
  3. this.pre = p;
  4. this.next = n;
  5. }
  6. public Node(){
  7. this.data = null;
  8. this.pre = null;
  9. this.next = null;
  10. }

下面我们看一下链表的构造函数实现:

  1. public MyList(){
  2. theSize = 0;
  3. Header = new Node<AnyType>(null,null,null);
  4. Tail   =  new Node<AnyType>(null,Header,null);
  5. Header.next = Tail;
  6. }

我们构造了一个带有头、尾节点的双向链表,头节点的Next指向尾节点,为节点的pre指向头节点。链表长度起始为0。

继续贴上链表类其它方法的实现,不解释了,应该比较清楚:

  1. public void add(AnyType item){
  2. Node<AnyType> aNode = new Node<AnyType>(item,null,null);
  3. Tail.pre.next = aNode;
  4. aNode.pre = Tail.pre;
  5. aNode.next = Tail;
  6. Tail.pre = aNode;
  7. theSize++;
  8. }
  9. public boolean isEmpty(){
  10. return ( theSize == 0);
  11. }
  12. public int size(){
  13. return theSize;
  14. }
  15. public AnyType get( int idx){
  16. if(idx > theSize-1 || idx < 0)
  17. throw new IndexOutOfBoundsException();
  18. Node<AnyType> current = new Node<AnyType>(null,Header,null);
  19. for(int i = 0; i<idx; i++)
  20. current = current.next;
  21. return current.data;
  22. }
  23. public void print(){
  24. Node<AnyType> current = Header.next;
  25. while(current.next != null){
  26. //如果AnyType是你自己定义 //的数据类型,那么请务必提供
  27. //一个toString方法,要么就不
  28. //要在链表里实现print方法。
  29. System.out.println(current.data.toString());
  30. current = current.next;
  31. }
  32. }

第二个例子是用迭代方法实现链表的例子,下面是类定义:

  1. public class MyListItr<Type> implements Iterable<Type> {
  2. private class Node<Type>{
  3. public Type data;
  4. public Node<Type> pre;
  5. public Node<Type> next;
  6. public Node(){}
  7. public Node(Type d, Node<Type> p, Node<Type> n){}
  8. }
  9. private Node<Type> Header;
  10. private Node<Type> Tail;
  11. private int theSize;
  12. public MyListItr(){}
  13. public void add(Type item){}
  14. public void print(){}
  15. public int size(){}
  16. @Override
  17. public Iterator<Type> iterator() {}
  18. private class MyListIterator implements Iterator<Type>{
  19. @Override
  20. public boolean hasNext() {}
  21. @Override
  22. public Type next() {}
  23. @Override
  24. public void remove() {}
  25. }
  26. }

这里主要说一下与前面例子不同的地方:MyListItr类实现了Java.lan.Itrable接口,因此我们必须实现其public Iterator<Type> iterator() {}方法,它的返回值是一个迭代器对象,那么我就定义一个内部私有类——MyListIterator,这个类实现了iterator接口。在public Iterator<Type> iterator() 方法中,我就构造这么一个MyListIterator的对象并返回。

Iterator接口有三个方法是我们必须实现的,hasNext,next和remove,这是迭代操作的最小集合了。对于不同的迭代器执行方式,我们可以定义多个类似MyListIterator这样的实现类,只要在链表类中的iterator() 方法中把具体实现类的对象返回给用户就OK了。

罗嗦两句:我感觉如果我们定义链表类时,如果不继承Iterable接口,而是直接在类内部提供 public theIterator Iterator() 方法,theIterator是一个自定义接口,继承自Iterator接口,这样我们可以提供遵循theIterator接口的各种迭代方式的不同实现类,并通过一个类厂方法在链表的public theIterator Iterator() 方法中把具体迭代实现类的对象交给用户,以此就可以根据不同的需求,提供链表的多种迭代方式。我觉得这种方法是可行的,但并没有具体实验。

下面只贴出链表iterator()方法和迭代实现类的MyListIterator代码,其它方法就不重复贴了:

    1. @Override
    2. public Iterator<Type> iterator() {
    3. return new MyListIterator();
    4. }
    5. private class MyListIterator implements Iterator<Type>{
    6. Node<Type> current = Header.next;
    7. @Override
    8. public boolean hasNext() {
    9. return (current != Tail);
    10. }
    11. @Override
    12. public Type next() {
    13.   if(!hasNext())
    14.     throw new IndexOutOfBoundsException();  
    15.   Type item = current.data;
    16.   current = current.next;
    17.   return item;
    18. }
    19. @Override
    20. public void remove() {
    21.   if( !hasNext())
    22.     throw new NoSuchElementException();
    23.   current.pre.next = current.next;
    24.   current.next.pre = current.pre;
    25.   current = current.next;
    26.   theSize--;
    27. }
    28. }

Java 链表的更多相关文章

  1. JAVA 链表操作:循环链表

    主要分析示例: 一.循环链表简述 二.单链表循环链表 三.双链表循环链表 一.循环链表简述 循环链表即链表形成了一个循环的结构,尾节点不再指向NULL,而是指向头节点HEAD,此时判定链表的结束是尾节 ...

  2. Java链表基本操作和Java.util.ArrayList

    Java链表基本操作和Java.util.ArrayList 今天做了一道<剑指offer>上的一道编程题“从尾到头打印链表”,具体要求如下:输入一个链表,按链表值从尾到头的顺序返回一个A ...

  3. JAVA链表中迭代器的实现

    注:本文代码出自<java数据结构和算法>一书. PS:本文中类的名字定义存在问题,Link9应改为Link.LinkList9应该为LinkList.由于在同包下存在该名称,所以在后面接 ...

  4. JAVA 链表操作:单链表和双链表

    主要讲述几点: 一.链表的简介 二.链表实现原理和必要性 三.单链表示例 四.双链表示例 一.链表的简介 链表是一种比较常用的数据结构,链表虽然保存比较复杂,但是在查询时候比较便捷,在多种计算机语言都 ...

  5. java 链表数据结构

    首先,单链表相对于队列的优势在于存储地址不是连续的,这样的意义在于,操作其中的某一个位置的元素时不需要对之前的其他元素都进行内存操作,大大的为我们的计算机减压了.下面直接进入正题: 先要定义一个结点类 ...

  6. 算法_栈与队列的Java链表实现

    链表是一个递归的数据结构,它或者为null,或者是指向一个结点的引用,该结点含有一个泛型的元素和指向另一个链表的引用.可以用一个内部类来定义节点的抽象数据类型: private class Node ...

  7. 学习记录 java 链表知识

    01.import java.util.HashMap; 02.import java.util.Scanner; 03.import java.util.Stack; 04. 05./** 06. ...

  8. Java链表的一些操作:

    [还有一些其他的算法提]http://blog.csdn.net/WalkingInTheWind/article/category/906980 [转]http://blog.csdn.net/lu ...

  9. 面试中的Java链表

    链表作为常考的面试题,并且本身比较灵活,对指针的应用较多.本文对常见的链表面试题Java实现做了整理. 链表节点定义如下: static class Node { int num; Node next ...

随机推荐

  1. visual studio 2015 开发android

    转载请注明: http://www.cnblogs.com/sunyl/p/5493249.html http://www.cnblogs.com/sunyl/ 最近有不少新闻, 甲骨文向谷歌索赔93 ...

  2. JMeter专题系列(七)聚合报告之 90% Line

    JMeter 官网原文: 90% Line - 90% of the samples took no more than this time. The remaining samples at lea ...

  3. [ASP.NET Core] Static File Middleware

    前言 本篇文章介绍ASP.NET Core里,用来处理静态档案的Middleware,为自己留个纪录也希望能帮助到有需要的开发人员. ASP.NET Core官网 结构 一个Web站台最基本的功能,就 ...

  4. jQuery实现侧边导航栏效果

    效果图: 效果体验:http://keleyi.com/keleyi/phtml/jqmenu/2.htm 以下是完整代码: <!DOCTYPE html> <html> &l ...

  5. 程序员用HTML5给女朋友制作的3D相册

    程序员给女朋友用HTML5制作的3D相册,使用鼠标拖拽,能看到3D旋转效果,点击相片,相片能放大,移近.程序员发挥自己的专长,这是那些不懂编程的人望尘莫及的.本相册使用了HTML5的画布技术,需要谷歌 ...

  6. 谷歌livereload插件使用

    1.插件下载地址:http://www.chromein.com/search_livereload_1.html 2.谷歌浏览器启用改插件 3.sublime 安装livereload插件,安装方法 ...

  7. Spring(5)—— 注解

    注解Annotation,是一种类似注释的机制,在代码中添加注解可以在之后某时间使用这些信息.跟注释不同的是,注释是给我们看到,java虚拟机不会编译,注解也是不编译的,但是我们可以通过反射机制来读取 ...

  8. CSS3过渡详解-遁地龙卷风

    第二版 0.环境准备 (1)过渡需要浏览器的支持,使用这些属性要加上浏览器厂商的前缀,我用的chrome49已经不需要前缀了, -o- Opera -webkit- Safari.Chrome -mo ...

  9. iOS 获取网络状态

    在iOS开发者,获取网络状态比较常用 -(NSString *)getNetWorkStates{ UIApplication *app = [UIApplication sharedApplicat ...

  10. Upgrade from SharePoint 2010 to SharePoint 2016

    [转]http://nikcharlebois.com/upgrade-from-sharepoint-2010-to-sharepoint-2016/ In this blog, I will go ...