用Java實現鏈表結構


  這里主要記錄了一下學習用Java實現鏈表的方法。假設你有一點Java基礎,了解接口、內部類的內容,同時也學過數據結構中鏈表的內容,對設計模式中的工廠方法和迭代方法知道一些,(因為這里將不介紹這些基礎知識,我的水平也講不清)又想了解在Java中實現鏈表,那么接着看吧。(最近讀嚴老師<應該沒記錯名字吧,如果錯了抱歉>的帖子說應該在博文中說明帖子的讀者范圍,不要浪費大家的時間,這里響應一下)。

首先聲明一下,本人菜鳥一只,近日閑來無事做做coding打發光陰,限於我對技術的認知水平,文中說的不對的地方一定不少,如果有熱心人能幫忙指出,不勝感激!!批評者,請口下留情,不要打擊了俺幼小地心靈。。。。。

正文:

    最近寫程序的過程中想用鏈表的方法把一些數據組織起來,C/C++的鏈表倒是比較熟,但是Java里還沒寫過。在網上搜了搜,Java中的鏈表應該是有以下幾種方法:

    按鏈表的組織形式分有ArrayListLinkList兩種。ArrayList內部其實是用數組的形式實現鏈表,比較適合鏈表大小確定或較少對鏈表進行增刪操作的情況,同時對每個鏈表節點的訪問時間都是constant;而LinkList內部以一個List實現鏈表,比較適合需要頻繁對鏈表進行操作的情況,對鏈表節點的訪問時間與鏈表長度有關O(N)

    另外,根據實現形式可以分為直接式(想不出什么合適的名字,姑且這樣吧)和使用Iterator(迭代模式)兩種方法。直接式的實現方法和C/C++中的寫法差不多;而使用Iterator時,需要實現java.lan中的Iterable接口(或者也可以自己在鏈表內部定義自己的Iterator method

    關於直接實現鏈表好,還是使用迭代模式好這個問題,有兩個帖子可以看看:

     1.  http://topic.csdn.net/t/20050722/17/4162226.html這篇帖子,雖然短小,但也說出了一些使用迭代模式設計鏈表的好處;

     2.后來又看到了http://www.java63.com/design_pattern/iterator_pattern.html這篇帖子,覺得說的比較清楚了。

    我這里再撿主要的說一下:

        使用迭代模式的優點:

           1,實現功能分離,簡化容器接口。讓容器只實現本身的基本功能,把迭代功能委讓給外部類實現,符合類的設計原則。

           2,隱藏容器的實現細節。

           3,為容器或其子容器提供了一個統一接口,一方面方便調用;另一方面使得調用者不必關注迭代器的實現細節。

           4,可以為容器或其子容器實現不同的迭代方法或多個迭代方法。

    我覺得第4點說的很好,對於一堆數據而言,不同的人(或業務邏輯)使用它的方式也不盡相同,定義一個theIterator繼承Iterator,不僅提供nexthasNext 以及remove這個最小的操作集合,同時也可以提供更多的其它方法。在theIterator的實現類中,具體實現不同的迭代方法,比如順序、逆序或根據其它語義進行遍歷等,再通過類廠的方式將一個theIterator實現的對象交給用戶使用。

下面我給出兩個例子:

    首先是直接式實現鏈表的例子,這個例子只提供了幾種鏈表操作的基本方法,僅用於示意:

 
public class MyList<AnyType> {

private class Node<AnyType>{

public Node<AnyType> pre;

public Node<AnyType> next;

public AnyType data;

public Node(AnyType d, Node<AnyType>p, Node<AnyType> n){}

public Node(){}

}

private int theSize;

private Node<AnyType> Header;

private Node<AnyType> Tail;

public MyList(){}

public void add(AnyType item){}

public boolean isEmpty(){}

public int size(){}

public AnyType get( int idx){}

public void print(){}

}

Node<AnyType>類定義了雙向鏈表中節點的結構,它是一個私有類,而其屬性和構造函數都是公有的,這樣,其父類可以直接訪問其屬性,而外部類根本不知道Node類的存在。Data是節點中的數據與,pre指向前一個Node節點,next指向后一個Node節點。其構造函數的實現如下,不解釋:

View Code
public Node(AnyType d, Node<AnyType>p, Node<AnyType> n){

this.data = d;

this.pre = p;

this.next = n;

}

public Node(){

this.data = null;

this.pre = null;

this.next = null;

}

 

下面我們看一下鏈表的構造函數實現:

View Code
public MyList(){

theSize = 0;

Header = new Node<AnyType>(null,null,null);

Tail = new Node<AnyType>(null,Header,null);

Header.next = Tail;

}

  我們構造了一個帶有頭、尾節點的雙向鏈表,頭節點的Next指向尾節點,為節點的pre指向頭節點。鏈表長度起始為0

繼續貼上鏈表類其它方法的實現,不解釋了,應該比較清楚:

View Code
public void add(AnyType item){

Node<AnyType> aNode = new Node<AnyType>(item,null,null);

Tail.pre.next = aNode;

aNode.pre = Tail.pre;

aNode.next = Tail;

Tail.pre = aNode;

theSize++;

}

public boolean isEmpty(){

return ( theSize == 0);

}

public int size(){

return theSize;

}

public AnyType get( int idx){

if(idx > theSize-1 || idx < 0)

throw new IndexOutOfBoundsException();



Node<AnyType> current = new Node<AnyType>(null,Header,null);



for(int i = 0; i<idx; i++)

current = current.next;

return current.data;

}

public void print(){

Node<AnyType> current = Header.next;

while(current.next != null){
//如果AnyType是你自己定義 //的數據類型,那么請務必提供
//一個toString方法,要么就不
//要在鏈表里實現print方法。
System.out.println(current.data.toString());

current = current.next;

}

}

 

第二個例子是用迭代方法實現鏈表的例子,下面是類定義:

View Code
public class MyListItr<Type> implements Iterable<Type> {

private class Node<Type>{

public Type data;

public Node<Type> pre;

public Node<Type> next;

public Node(){}

public Node(Type d, Node<Type> p, Node<Type> n){}

}





private Node<Type> Header;

private Node<Type> Tail;

private int theSize;



public MyListItr(){}





public void add(Type item){}



public void print(){}



public int size(){}

@Override

public Iterator<Type> iterator() {}



private class MyListIterator implements Iterator<Type>{

@Override

public boolean hasNext() {}

@Override

public Type next() {}

@Override

public void remove() {}

}

}

    這里主要說一下與前面例子不同的地方:MyListItr類實現了java.lan.Itrable接口,因此我們必須實現其public Iterator<Type> iterator() {}方法,它的返回值是一個迭代器對象,那么我就定義一個內部私有類——MyListIterator,這個類實現了iterator接口。在public Iterator<Type> iterator() 方法中,我就構造這么一個MyListIterator的對象並返回。

    Iterator接口有三個方法是我們必須實現的,hasNextnextremove,這是迭代操作的最小集合了。對於不同的迭代器執行方式,我們可以定義多個類似MyListIterator這樣的實現類,只要在鏈表類中的iterator() 方法中把具體實現類的對象返回給用戶就OK了。

   羅嗦兩句:我感覺如果我們定義鏈表類時,如果不繼承Iterable接口,而是直接在類內部提供 public theIterator Iterator() 方法,theIterator是一個自定義接口,繼承自Iterator接口,這樣我們可以提供遵循theIterator接口的各種迭代方式的不同實現類,並通過一個類廠方法在鏈表的public theIterator Iterator() 方法中把具體迭代實現類的對象交給用戶,以此就可以根據不同的需求,提供鏈表的多種迭代方式。我覺得這種方法是可行的,但並沒有具體實驗。

   下面只貼出鏈表iterator()方法和迭代實現類的MyListIterator代碼,其它方法就不重復貼了:

@Override

public Iterator<Type> iterator() {

return new MyListIterator();

}

private class MyListIterator implements Iterator<Type>{

Node<Type> current = Header.next;

@Override

public boolean hasNext() {

return (current != Tail);

}

@Override

public Type next() {

  if(!hasNext())

    throw new IndexOutOfBoundsException();  

  Type item = current.data;

  current = current.next;

  return item;
}

@Override

public void remove() {

  if( !hasNext())

    throw new NoSuchElementException();

  current.pre.next = current.next;
  current.next.pre = current.pre;
  current = current.next;

  theSize--;
}

}

測試代碼:

View Code
public class MyListTest {

/**

*
@param args

*/

public static void main(String[] args) {



MyList<Integer> intList = new MyList<Integer>();

for (int i = 0; i < 10; i++) {

intList.add(i);

}

intList.print();

MyListItr<ItemInfo> itrList = new MyListItr<ItemInfo>();

for (int i = 0; i < 10; i++) {

ItemInfo aItem = new ItemInfo("name_" + i, "score_" + i);

itrList.add(aItem);

}

itrList.print();



System.out.println("=======print using iterator type_1==========");

Iterator<ItemInfo> Itor = itrList.iterator();

for (ItemInfo str : itrList)

System.out.println(str);





System.out.println("=======print using iterator type_2==========");

while(Itor.hasNext())

System.out.println(Itor.next().toString());



System.out.println("-------------------after remove----------------");

while (Itor.hasNext())

Itor.remove();

while(Itor.hasNext())

System.out.println(Itor.next().toString());

}

}

   其中 ItemInfo的定義如下:

View Code
public class ItemInfo {


String name;

String score;

public ItemInfo(String n, String s){

name = n; score = s;

}

public ItemInfo(){

name = null; score = null;

}

public String toString(){

String str = name +" "+ score;

return str;

}

}

    至此,Java實現鏈表的方法基本上也就清楚了,希望我說清楚了,不要讓各位如同嚼蠟:) 這里是一個簡單的例子:MYLList

    下一步我想做以下工作:

        試一下通過類廠的方法提供多種鏈表的迭代方式;

        如何讓多線程訪問鏈表時保證操作不亂掉。。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM