链表详述

链接点(Link)

       在链表中,每个数据项都被包含在“链接点”(Link)中。一个链接点是某个类的对象,这个类一般叫做Link,因为一个链表中,有许多类似的链接点,所以有必要用一个不同于链表的类来表达链接点,每个Link对象中都包含一个对下一个链接点引用的字段,(通常叫做next)。但是链表(LinkList)本身的对象中有一个字段指向对第一个链接点的引用。
       链表不同于数组的主要特点之一是,在一个数组中每一项占用一个特定的位置,这个位置可以用一个下标号直接访问,它就像一排房子,你可以凭地址找到其中特定的一间,在链表中,寻找一个特定的元素的唯一方法就是沿着这个元素一直向下寻找,不能直接访问到数据,必须使用数据之间的关系来定位它,你从第一项开始,到第二项,然后到第二项,到第三项,知道发现要找的那个数据项。

单链表

利用面向对象的方法实现的单链表的java代码

//Link类
//此类中的iData和dData是一个节点中存储的数据,在实际应用中并非是这样的,
//可以是多个数据,或者是存储一个对象如这样:
//class Link
//   {
//   public Person person;          //data item
//   public Link next;              // next link in list
//   }
//数据类型可以是私有的,当设置成私有时,必须添加set和get方法
class Link
   {
   public int iData;              // data item
   public double dData;           // data item
   public Link next;              // next link in list
// -------------------------------------------------------------
   public Link(int id, double dd) // constructor
      {
      iData = id;                 // initialize data
      dData = dd;                 // ('next' is automatically
      }                           //  set to null)
// -------------------------------------------------------------
   public void displayLink()      // display ourself
      {
      System.out.print("{" + iData + ", " + dData + "} ");
      }
   }  // end class Link

//LinkList类
class LinkList
   {
   private Link first;            // ref to first link on list

// -------------------------------------------------------------
   public LinkList()              // constructor
      {
      first = null;               // no links on list yet
      }
// -------------------------------------------------------------
   public boolean isEmpty()       // true if list is empty
      {
      return (first==null);
      }
// -------------------------------------------------------------
                                  // insert at start of list
   public void insertFirst(int id, double dd)
      {                           // make new link
      Link newLink = new Link(id, dd);
      newLink.next = first;       // newLink --> old first
      first = newLink;            // first --> newLink
      }
// -------------------------------------------------------------
   public Link deleteFirst()      // delete first item
      {                           // (assumes list not empty)
      Link temp = first;          // save reference to link
      first = first.next;         // delete it: first-->old next
      return temp;                // return deleted link
      }
// -------------------------------------------------------------
//查找指定位置的节点
   public Link find(int key)      // find link with given key
      {                           // (assumes non-empty list)
      Link current = first;              // start at 'first'
      while(current.iData != key)        // while no match,
         {
         if(current.next == null)        // if end of list,
            return null;                 // didn't find it
         else                            // not end of list,
            current = current.next;      // go to next link
         }
      return current;                    // found it
      }
// -------------------------------------------------------------
//删除指定位置的节点
   public Link delete(int key)    // delete link with given key
      {                           // (assumes non-empty list)
      Link current = first;              // search for link
      Link previous = first;
      while(current.iData != key)
         {
         if(current.next == null)
            return null;                 // didn't find it
         else
            {
            previous = current;          // go to next link
            current = current.next;
            }
         }                               // found it
      if(current == first)               // if first link,
         first = first.next;             //    change first
      else                               // otherwise,
         previous.next = current.next;   //    bypass it
      return current;
      }
// -------------------------------------------------------------
   public void displayList()
      {
      System.out.print("List (first-->last): ");
      Link current = first;       // start at beginning of list
      while(current != null)      // until end of list,
         {
         current.displayLink();   // print data
         current = current.next;  // move to next link
         }
      System.out.println("");
      }
// -------------------------------------------------------------
   }  // end class LinkList

class LinkListApp
   {
   public static void main(String[] args)
      {
      LinkList theList = new LinkList();  // make new list

      theList.insertFirst(22, 2.99);      // insert four items
      theList.insertFirst(44, 4.99);
      theList.insertFirst(66, 6.99);
      theList.insertFirst(88, 8.99);

      theList.displayList();              // display list

      while( !theList.isEmpty() )         // until it's empty,
         {
         Link aLink = theList.deleteFirst();   // delete link
         System.out.print("Deleted ");         // display it
         aLink.displayLink();
         System.out.println("");
         }
      theList.displayList();              // display list
      }  // end main()
   }  // end class LinkListApp

其他方法

       上述代码已经提供可在表头插入和删除节点的方法,以及查找和删除一个指定链接点的方法,还可以在想象其他的有用的方法,比如,insertAfter()可以查找一个含有特定关键字的链接点,然后再他后面插入一个新的链接点。后续的笔记中写迭代器的时候,应该会看到这样的方法。

双端链表

       双端链表与传统的链表非常相似,但是他有一个新增的特性,即对最后一个链接点的引用,就像对第一个链接点的引用一样,对最后一个链接点的引用允许像在表头一样,在表尾直接插入一个链接点,当然,仍然可以在蒲绒的单链表的表尾插入一个链接点,方法时遍历整个链表直到到达表尾,但是这种方法效率很低,像访问表头一样访问表尾的特性,使双端链表更适合与一些普通链表不方便操作的场合,队列的实现就是这样一个情况,顺表提一句,不要把双端链表和双向链表搞混,他们是不一样的。

双端链表实现的java代码

// firstLastList.java
// demonstrates list with first and last references
// to run this program: C>java FirstLastApp

class Link
   {
   public long dData;                 // data item
   public Link next;                  // next link in list
// -------------------------------------------------------------
   public Link(long d)                // constructor
      { dData = d; }
// -------------------------------------------------------------
   public void displayLink()          // display this link
      { System.out.print(dData + " "); }
// -------------------------------------------------------------
   }  // end class Link

class FirstLastList
   {
   private Link first;               // ref to first link
   private Link last;                // ref to last link
// -------------------------------------------------------------
   public FirstLastList()            // constructor
      {
      first = null;                  // no links on list yet
      last = null;
      }
// -------------------------------------------------------------
   public boolean isEmpty()          // true if no links
      { return first==null; }
// -------------------------------------------------------------
   public void insertFirst(long dd)  // insert at front of list
      {
      Link newLink = new Link(dd);   // make new link

      if( isEmpty() )                // if empty list,
         last = newLink;             // newLink <-- last
      newLink.next = first;          // newLink --> old first
      first = newLink;               // first --> newLink
      }
// -------------------------------------------------------------
   public void insertLast(long dd)   // insert at end of list
      {
      Link newLink = new Link(dd);   // make new link
      if( isEmpty() )                // if empty list,
         first = newLink;            // first --> newLink
      else
         last.next = newLink;        // old last --> newLink
      last = newLink;                // newLink <-- last
      }
// -------------------------------------------------------------
   public long deleteFirst()         // delete first link
      {                              // (assumes non-empty list)
      long temp = first.dData;
      if(first.next == null)         // if only one item
         last = null;                // null <-- last
      first = first.next;            // first --> old next
      return temp;
      }
// -------------------------------------------------------------
   public void displayList()
      {
      System.out.print("List (first-->last): ");
      Link current = first;          // start at beginning
      while(current != null)         // until end of list,
         {
         current.displayLink();      // print data
         current = current.next;     // move to next link
         }
      System.out.println("");
      }
// -------------------------------------------------------------
   }  // end class FirstLastList

class FirstLastApp
   {
   public static void main(String[] args)
      {                              // make a new list
      FirstLastList theList = new FirstLastList();

      theList.insertFirst(22);       // insert at front
      theList.insertFirst(44);
      theList.insertFirst(66);

      theList.insertLast(11);        // insert at rear
      theList.insertLast(33);
      theList.insertLast(55);

      theList.displayList();         // display the list

      theList.deleteFirst();         // delete first two items
      theList.deleteFirst();

      theList.displayList();         // display again
      }  // end main()
   }  // end class FirstLastApp

注意:双端链表插入和删除方法和普通链表相应部分类似,然而,两个插入方法都要考虑一种特殊情况,即插入前链表是空的,不幸的是,用双端链表也不能有助于删除最后一个链接点,因为没有一个引用指向倒数第二个链接点,如果最后一个链接点被删除,倒数第二个链接点的next字段应该变成null值,为了方便的删除最后一个链接点,需要一个双向链表,后续后写笔记。(当然也可以遍历整个链表找到最后一个链接点,但是那样做效率不高)。

链表的效率

       在表头插入和删除速度很快,仅需要改变一两个引用值,所以花费O(1)的时间。平均起来,查找,删除和在指定链接点后面插入都需要搜索链表中的一半链接点,需要O(N)次比较,在数组中执行这些操作也需要O(N)次比较,但是链表仍然要快一些,因为当插入和删除链接点时,链表不需要移动任何东西,增加的效率是很显著的,特别是当复制时间远远大于比较时间的时候。
       当然,链表比数组优越的另外一个重要的方面是链表需要多少内存就可以用多少内存,并且可以扩展到所有可用内存,数组的大小在他创建的时候就固定了,所以经常由于数组太大导致效率低下,或者数组太小导致空间溢出,向量是一种可扩展的数组,它可以通过可变长度解决这个问题,但是他经常只允许以固定的大小增量扩展(例如快要溢出的时候,就增加一倍数组容量),这个解决方案在内存使用效率上来说还是要比聊表的低。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值