數據結構Java實現03----單向鏈表的插入和刪除

文本主要內容:java

  • 鏈表結構
  • 單鏈表代碼實現
  • 單鏈表的效率分析

1、鏈表結構: (物理存儲結構上不連續,邏輯上連續;大小不固定)           算法

概念:編程

  鏈式存儲結構是基於指針實現的。咱們把一個數據元素和一個指針稱爲結點數組

        數據域:存數數據元素信息的域。數據結構

        指針域:存儲直接後繼位置的域。dom

  鏈式存儲結構是用指針把相互直接關聯的結點(即直接前驅結點或直接後繼結點)連接起來。鏈式存儲結構的線性表稱爲鏈表。 ide

鏈表類型:函數

  根據鏈表的構造方式的不一樣能夠分爲:測試

  • 單向鏈表
  • 單向循環鏈表
  • 雙向循環鏈表

 

2、單鏈表:大數據

概念:

    鏈表的每一個結點中只包含一個指針域,叫作單鏈表(即構成鏈表的每一個結點只有一個指向直接後繼結點的指針

單鏈表中每一個結點的結構:

912d954f-de3f-4d35-bd01-3c4f87d9993b

一、頭指針和頭結點:

單鏈表有帶頭結點結構和不帶頭結點結構兩種。

「鏈表中第一個結點的存儲位置叫作頭指針」,若是鏈表有頭結點,那麼頭指針就是指向頭結點的指針

頭指針所指的不存放數據元素的第一個結點稱做頭結點(頭結點指向首元結點)。頭結點的數據域通常不放數據(固然有些狀況下也可存放鏈表的長度、用作監視哨等)

存放第一個數據元素的結點稱做第一個數據元素結點,或稱首元結點

以下圖所示:

5fdb1362-fd98-4d23-9932-271f2ab9d480

不帶頭結點的單鏈表以下:

14c9aae5-c9fc-4dbe-b5c4-29c05ed84c5e

帶頭結點的單鏈表以下圖:

a9afd20d-da0f-4c59-a2d6-d8eb8175933b

關於頭指針和頭結點的概念區分,能夠參考以下博客:

http://blog.csdn.net/hitwhylz/article/details/12305021

二、不帶頭結點的單鏈表的插入操做:

912a8385-5a98-48b8-a515-8dfd9347042d

上圖中,是不帶頭結點的單鏈表的插入操做。若是咱們在非第一個結點前進行插入操做,只須要a(i-1)的指針域指向s,而後將s的指針域指向a(i)就好了;若是咱們在第一個結點前進行插入操做,頭指針head就要等於新插入結點s,這和在非第一個數據元素結點前插入結點時的狀況不一樣。另外,還有一些不一樣狀況須要考慮。

所以算法對這兩種狀況就要分別設計實現方法

三、帶頭結點的單鏈表的插入操做:(操做統一,推薦)

95b7d67d-ddaa-4b00-99f6-c1acf4f708b1

上圖中,若是採用帶頭結點的單鏈表結構,算法實現時,p指向頭結點,改變的是p指針的next指針的值(改變頭結點的指針域),而頭指針head的值不變

所以,算法實現方法比較簡單,其操做與對其它結點的操做統一

 

問題1:頭結點的好處:

  頭結點即在鏈表的首元結點以前附設的一個結點,該結點的數據域中不存儲線性表的數據元素,其做用是爲了對鏈表進行操做時,能夠對空表、非空表的狀況以及對首元結點進行統一處理,編程更方便。

問題2:如何表示空表:

  無頭結點時,當頭指針的值爲空時表示空表;
  有頭結點時,當頭結點的指針域爲空時表示空表。

 

以下圖所示:

問題3:頭結點的數據域內裝的是什麼?

頭結點的數據域能夠爲空,也可存放線性表長度等附加信息,但此結點不能計入鏈表長度值

 

3、單項鍊表的代碼實現:

一、結點類:

單鏈表是由一個一個結點組成的,所以,要設計單鏈表類,必須先設計結點類。結點類的成員變量有兩個:一個是數據元素,另外一個是表示下一個結點的對象引用(即指針)。

步驟以下:

(1)頭結點的構造(設置指針域便可)

(2)非頭結點的構造

(3)得到當前結點的指針域

(4)得到當前結點數據域的值

(5)設置當前結點的指針域

(6)設置當前結點數據域的值

注:相似於get和set方法,成員變量是數據域和指針域。

代碼實現:

(1)List.java:(鏈表自己也是線性表,只不過物理存儲上不連續)

//線性表接口
public interface List {
    //得到線性表長度
    public int size();

    //判斷線性表是否爲空
    public boolean isEmpty();

    //插入元素
    public void insert(int index, Object obj) throws Exception;

    //刪除元素
    public void delete(int index) throws Exception;

    //獲取指定位置的元素
    public Object get(int index) throws Exception;
}

 

(2)Node.java:結點類

//結點類
public class Node {

    Object element; //數據域
    Node next;  //指針域

    //頭結點的構造方法
    public Node(Node nextval) {
        this.next = nextval;
    }

    //非頭結點的構造方法
    public Node(Object obj, Node nextval) {
        this.element = obj;
        this.next = nextval;
    }

    //得到當前結點的指針域
    public Node getNext() {
        return this.next;
    }

    //得到當前結點數據域的值
    public Object getElement() {
        return this.element;
    }
    //設置當前結點的指針域
    public void setNext(Node nextval) {
        this.next = nextval;
    }

    //設置當前結點數據域的值
    public void setElement(Object obj) {
        this.element = obj;
    }

    public String toString() {
        return this.element.toString();
    }
}

 

二、單鏈表類:

單鏈表類的成員變量至少要有兩個:一個是頭指針,另外一個是單鏈表中的數據元素個數。可是,若是再增長一個表示單鏈表當前結點位置的成員變量,則有些成員函數的設計將更加方便。

代碼實現:

(3)LinkList.java:單向鏈表類(核心代碼)

 1 //單向鏈表類
 2 public class LinkList implements List {
 3 
 4     Node head; //頭指針
 5     Node current;//當前結點對象
 6     int size;//結點個數
 7     
 8     //初始化一個空鏈表
 9     public LinkList()
10     {
11         //初始化頭結點,讓頭指針指向頭結點。而且讓當前結點對象等於頭結點。
12         this.head = current = new Node(null);
13         this.size =0;//單向鏈表,初始長度爲零。
14     }
15     
16     //定位函數,實現當前操做對象的前一個結點,也就是讓當前結點對象定位到要操做結點的前一個結點。
17     //好比咱們要在a2這個節點以前進行插入操做,那就先要把當前節點對象定位到a1這個節點,而後修改a1節點的指針域
18     public void index(int index) throws Exception
19     {
20         if(index <-1 || index > size -1)
21         {
22           throw new Exception("參數錯誤!");    
23         }
24         //說明在頭結點以後操做。
25         if(index==-1)    //由於第一個數據元素結點的下標是0,那麼頭結點的下標天然就是-1了。
26             return;
27         current = head.next;
28         int j=0;//循環變量
29         while(current != null&&j<index)
30         {
31             current = current.next;
32             j++;
33         }
34         
35     }    
36     
37     @Override
38     public void delete(int index) throws Exception {
39         // TODO Auto-generated method stub
40         //判斷鏈表是否爲空
41         if(isEmpty())
42         {
43             throw new Exception("鏈表爲空,沒法刪除!");
44         }
45         if(index <0 ||index >size)
46         {
47             throw new Exception("參數錯誤!");
48         }
49         index(index-1);//定位到要操做結點的前一個結點對象。
50         current.setNext(current.next.next);
51         size--;
52     }
53 
54     @Override
55     public Object get(int index) throws Exception {
56         // TODO Auto-generated method stub
57         if(index <-1 || index >size-1)
58         {
59             throw new Exception("參數非法!");
60         }
61         index(index);
62         
63         return current.getElement();
64     }
65 
66     @Override
67     public void insert(int index, Object obj) throws Exception {
68         // TODO Auto-generated method stub
69         if(index <0 ||index >size)
70         {
71             throw new Exception("參數錯誤!");
72         }
73         index(index-1);//定位到要操做結點的前一個結點對象。
74         current.setNext(new Node(obj,current.next));
75         size++;
76     }
77 
78     @Override
79     public boolean isEmpty() {
80         // TODO Auto-generated method stub
81         return size==0;
82     }
83 
84     @Override
85     public int size() {
86         // TODO Auto-generated method stub
87         return this.size;
88     }
89     
90     
91 }

三、測試類:(單鏈表的應用)

使用單鏈表創建一個線性表,依次輸入十個0-99之間的隨機數,刪除第5個元素,打印輸出該線性表。

(4)Test.java:

 1 public class Test {
 2 
 3     public static void main(String[] args) throws Exception {
 4         // TODO Auto-generated method stub
 5         LinkList list = new LinkList();
 6         for (int i = 0; i < 10; i++) {
 7             int temp = ((int) (Math.random() * 100)) % 100;
 8             list.insert(i, temp);
 9             System.out.print(temp + " ");
10         }
11 
12         list.delete(4);
13         System.out.println("\n------刪除第五個元素以後-------");
14         for (int i = 0; i < list.size; i++) {
15             System.out.print(list.get(i) + " ");
16         }
17     }
18 
19 }

運行效果:

8ccaab32-e80c-4e9b-88d4-bbdbf1a80f90

 

4、開發可用的鏈表:

對於鏈表實現,Node類是整個操做的關鍵,可是首先來研究一下以前程序的問題:Node是一個單獨的類,那麼這樣的類是能夠被用戶直接使用的,可是這個類由用戶直接去使用,沒有任何的意義,即:Node這個類有用,可是不能讓用戶去用,只能讓LinkList類去調用,內部類Node中完成

因而,咱們須要把Node類定義爲內部類,而且在Node類中去完成addNode和delNote等操做。使用內部類的最大好處是能夠和外部類進行私有操做的互相訪問

注:內部類訪問的特色是:內部類能夠直接訪問外部類的成員,包括私有;外部類要訪問內部類的成員,必須先建立對象。

一、增長數據:

  • public Boolean add(數據 對象)

代碼實現:

(1)LinkList.java:(核心代碼)

 1 public class LinkList {
 2     private Node root; //定義一個根節點
 3 
 4     //方法:增長節點
 5     public boolean add(String data) {  6 
 7         if (data == null) {     // 若是添加的是一個空數據,那增長失敗
 8             return false;
 9         }
10 
11         // 將數據封裝爲節點,目的:節點有next能夠處理關係
12         Node newNode = new Node(data); 13         // 鏈表的關鍵就在於根節點
14         if (root == null) {  //若是根節點是空的,那麼新添加的節點就是根節點。(第一次調用add方法時,根節點固然是空的了)
15             root = newNode; 16         } else { 17  root.addNode(newNode); 18 
19         }
20 
21         return true;
22 
23     }
24 
25 
26     //定義一個節點內部類(假設要保存的數據類型是字符串)
27     //比較好的作法是,將Node定義爲內部類,在這裏面去完成增刪、等功能,而後由LinkList去調用增、刪的功能
28     class Node {
29         private String data;
30         private Node next;  //next表示:下一個節點對象(單鏈表中)
31 
32         public Node(String data) {
33             this.data = data;
34         }
35 
36         public void addNode(Node newNode) {
37 
38             //下面這段用到了遞歸,須要反覆理解
39             if (this.next == null) {   // 遞歸的出口:若是當前節點以後沒有節點,說明我能夠在這個節點後面添加新節點
40                 this.next = newNode;   //添加新節點
41             } else { 42                 this.next.addNode(newNode);  //向下繼續判斷,直到當前節點以後沒有節點爲止
43 
44             }
45         }
46     }
47 }

代碼解釋:

14行:若是咱們第一次調用add方法,那根結點確定是空的,此時add的是根節點。

當繼續調用add方法時,此時是往根節點後面添加數據,須要用到遞歸(42行),這個遞歸須要在內部類中去完成。遞歸這段代碼須要去反覆理解。

(2)LinkListDemo.java:  

public class LinkListDemo {

    public static void main(String[] args) {
        LinkList list = new LinkList();
        boolean flag = list.add("haha");
        System.out.println(flag);
    }

}

運行效果:

 

 

二、增長多個數據:

  • public boolean addAll(數據 對象 [] ) 

上面的操做是每次增長了一個對象,那麼若是如今要求增長多個對象呢,例如:增長對象數組。能夠採用循環數組的方式,每次都調用add()方法。 

在上面的(1)LinkList.java中加入以下代碼:

1     //方法:增長一組數據
2     public boolean addAll(String data[]) {     // 一組數據
3         for (int x = 0 ; x < data.length ; x ++) {
4             if (!this.add(data[x])) { // 只要有一次添加不成功,那就是添加失敗
5                 return false ;
6             }
7         }
8         return true ;
9     }

 

 三、統計數據個數:

  • public int size()

 在一個鏈表之中,會保存多個數據(每個數據都被封裝爲Node類對象),那麼要想取得這些保存元素的個數,能夠增長一個size()方法完成。

具體作法以下:

在上面的(1)LinkList.java中增長一個統計的屬性count:

private int size ; // 統計個數

當用戶每一次調用add()方法增長新數據的時候應該作出統計:(下方第18行代碼)

 1     //添加節點
 2     public boolean add(String data) {
 3 
 4         if (data == null) {     // 若是添加的是一個空數據,那增長失敗
 5             return false;
 6         }
 7 
 8         // 將數據封裝爲節點,目的:節點有next能夠處理關係
 9         Node newNode = new Node(data);
10         // 鏈表的關鍵就在於根節點
11         if (root == null) {  //若是根節點是空的,那麼新添加的節點就是根節點。(第一次調用add方法時,根節點固然是空的了)
12             root = newNode;
13         } else {
14             root.addNode(newNode);
15 
16         }
17 
18         this.size++; 19         return true;
20 
21     }

 而size()方法就是簡單的將count這個變量的內容返回:

    //獲取數據的長度
    public int size() {
        return this.size;
    }

 

四、判斷是不是空鏈表:

  • public boolean isEmpty()

所謂的空鏈表指的是鏈表之中不保存任何的數據,實際上這個null能夠經過兩種方式判斷:一種判斷鏈表的根節點是否爲null,另一個是判斷保存元素的個數是否爲0。

在LinkList.java中添加以下代碼:

    //判斷是否爲空鏈表
    public boolean isEmpty() {
        return this.size == 0;
    }

 

五、查找數據是否存在:

  • public boolean contains(數據 對象)

如今若是要想查詢某個數據是否存在,那麼基本的操做原理:逐個盤查,盤查的具體實現仍是應該交給Node類去處理,可是在盤查以前必須有一個前提:有數據存在。

在LinkList.java中添加查詢的操做:

1     //查詢數據是否存在
2     public boolean contains(String data) {      // 查找數據
3         // 根節點沒有數據,查找的也沒有數據
4         if (this.root == null || data == null) {
5             return false;        // 不須要進行查找了
6         }
7         return this.root.containsNode(data);        // 交給Node類處理
8     }

緊接着,在Node類之中,完成具體的查詢,查詢的流程:
  判斷當前節點的內容是否知足於查詢內容,若是知足返回true;
  若是當前節點的內容不知足,則向後繼續查,若是已經沒有後續節點了,則返回false。

代碼實現:

 1       //判斷節點是否存在
 2         public boolean containsNode(String data) {      // 查找數據
 3             if (data.equals(this.data)) {     // 與當前節點數據吻合
 4                 return true;
 5             } else {       // 與當前節點數據不吻合
 6                 if (this.next != null) {   // 還有下一個節點
 7                     return this.next.containsNode(data);
 8                 } else {       // 沒有後續節點
 9                     return false;        // 查找不到
10                 }
11             }
12         }

 

六、刪除數據:

  • public boolean remove(數據 對象)

 在LinkList.java中加入以下代碼:

 1    //方法:刪除數據
 2     public boolean remove(String data) { //要刪除的節點,假設每一個節點的data都不同
 3 
 4         if (!this.contains(data)) { //要刪除的數據不存在
 5             return false;
 6         }
 7 
 8         if (root != null) {
 9             if (root.data.equals(data)) {  //說明根節點就是須要刪除的節點
10                 root = root.next;  //讓根節點的下一個節點成爲根節點,天然就把根節點頂掉了嘛(不像數組那樣,要將後面的數據在內存中總體挪一位)
11             } else {  //不然
12                 root.removeNode(data);
13             }
14         }
15         size--;
16         return true;
17 
18     }

注意第2代碼中,咱們是假設刪除的這個String字符串是惟一的,否則就無法刪除了。

刪除時,咱們須要從根節點開始判斷,若是根節點是須要刪除的節點,那就直接刪除,此時下一個節點變成了根節點。

而後,在Node類中作節點的刪除:

        //刪除節點
        public void removeNode(String data) {
            if (this.next != null) {
                if (this.next.data.equals(data)) {
                    this.next = this.next.next;
                } else {
                    this.next.removeNode(data);
                }
            }

        }

 

七、輸出全部節點:

 在LinkList.java中加入以下代碼:

1  //輸出全部節點
2     public void print() {
3         if (root != null) {
4             System.out.print(root.data);
5             root.printNode();
6             System.out.println();
7         }
8     }

而後,在Node類中作節點的輸出:

1  //輸出全部節點
2         public void printNode() {
3             if (this.next != null) {
4                 System.out.print("-->" + this.next.data);
5                 this.next.printNode();
6             }
7         }

  

八、取出所有數據:

  • public 數據 [] toArray()

對於鏈表的這種數據結構,最爲關鍵的是兩個操做:刪除、取得所有數據。

在LinkList類之中須要定義一個操做數組的腳標:  

    private int foot = 0;      // 操做返回數組的腳標

在LinkList類中定義返回數組,必須以屬性的形式出現,只有這樣,Node類才能夠訪問這個數組並進行操做:

    private String [] retData ;       // 返回數組

在LinkList類之中增長toArray()的方法:

 1 //方法:獲取所有數據
 2     public String[] toArray() {
 3         if (this.size == 0) {
 4             return null; // 沒有數據
 5         }
 6         this.foot = 0;       // 清零
 7         this.retData = new String[this.size];     // 開闢數組大小
 8         this.root.toArrayNode();
 9         return this.retData;
10     }

修改Node類的操做,增長toArrayNode()方法:

1         //獲取所有數據
2         public void toArrayNode() {
3             LinkList.this.retData[LinkList.this.foot++] = this.data;
4             if (this.next != null) {
5                 this.next.toArrayNode();
6             }
7         }

 

不過,按照以上的方式進行開發,每一次調用toArray()方法,都要重複的進行數據的遍歷,若是在數據沒有修改的狀況下,這種作法是一種很是差的作法,最好的作法是增長一個修改標記,若是發現數據增長了或刪除的話,表示要從新遍歷數據。

private boolean changeFlag = true ;
 // changeFlag == true:數據被更改了,則須要從新遍歷
// changeFlag == false:數據沒有更改,不須要從新遍歷

而後,咱們修改LinkList類中的toArray()方法:(其餘代碼保持不變)

//方法:獲取所有數據
    public String[] toArray() {
        if (this.size == 0) {
            return null; // 沒有數據
        }
        this.foot = 0;       // 清零
        if (this.changeFlag == true) {          // 內容被修改了,須要從新取
            this.retData = new String[this.size];     // 開闢數組大小
            this.root.toArrayNode();
        }
        return this.retData;
    }

 

九、根據索引位置取得數據:

  • public 數據 get(int index)

在一個鏈表之中會有多個節點保存數據,如今要求能夠取得指定節點位置上的數據。可是在進行這一操做的過程之中,有一個小問題:若是要取得數據的索引超過了數據的保存個數,那麼是沒法取得的。

在LinkList類之中,增長一個get()方法:

1  //方法:根據索引取得數據
2     public String get(int index) {
3         if (index > this.size) {         // 超過個數
4             return null;          // 返回null
5         }
6         this.foot = 0;       // 操做foot來定義腳標
7         return this.root.getNode(index);
8     }

在Node類之中配置getNode()方法:

1        //根據索引位置獲取數據
2         public String getNode(int index) {
3             if (LinkList.this.foot++ == index) {     // 當前索引爲查找數值
4                 return this.data;
5             } else {
6                 return this.next.getNode(index);
7             }
8         }

 

十、清空鏈表:

  • public void clear()

 全部的鏈表被root拽着,這個時候若是root爲null,那麼後面的數據都會斷開,就表示都成了垃圾:

//清空鏈表
    public void clear() {
        this.root = null;
        this.size = 0;
    }

 

總結:

上面的10條方法中,LinkList的完整代碼以下:

  1 /**
  2  * Created by smyhvae on 2015/8/27.
  3  */
  4 
  5 public class LinkList {
  6 
  7     private int size;
  8     private Node root; //定義一個根節點
  9 
 10     private int foot = 0;      // 操做返回數組的腳標
 11     private String[] retData;       // 返回數組
 12     private boolean changeFlag = true;
 13     // changeFlag == true:數據被更改了,則須要從新遍歷
 14     // changeFlag == false:數據沒有更改,不須要從新遍歷
 15 
 16 
 17     //添加數據
 18     public boolean add(String data) {
 19 
 20         if (data == null) {     // 若是添加的是一個空數據,那增長失敗
 21             return false;
 22         }
 23 
 24         // 將數據封裝爲節點,目的:節點有next能夠處理關係
 25         Node newNode = new Node(data);
 26         // 鏈表的關鍵就在於根節點
 27         if (root == null) {  //若是根節點是空的,那麼新添加的節點就是根節點。(第一次調用add方法時,根節點固然是空的了)
 28             root = newNode;
 29         } else {
 30             root.addNode(newNode);
 31 
 32         }
 33 
 34         this.size++;
 35         return true;
 36 
 37     }
 38 
 39 
 40     //方法:增長一組數據
 41     public boolean addAll(String data[]) {     // 一組數據
 42         for (int x = 0; x < data.length; x++) {
 43             if (!this.add(data[x])) { // 只要有一次添加不成功,那就是添加失敗
 44                 return false;
 45             }
 46         }
 47         return true;
 48     }
 49 
 50     //方法:刪除數據
 51     public boolean remove(String data) { //要刪除的節點,假設每一個節點的data都不同
 52 
 53         if (!this.contains(data)) { //要刪除的數據不存在
 54             return false;
 55         }
 56 
 57         if (root != null) {
 58             if (root.data.equals(data)) {  //說明根節點就是須要刪除的節點
 59                 root = root.next;  //讓根節點的下一個節點成爲根節點,天然就把根節點頂掉了嘛(不像數組那樣,要將後面的數據在內存中總體挪一位)
 60             } else {  //不然
 61                 root.removeNode(data);
 62             }
 63         }
 64         size--;
 65         return true;
 66 
 67     }
 68 
 69     //輸出全部節點
 70     public void print() {
 71         if (root != null) {
 72             System.out.print(root.data);
 73             root.printNode();
 74             System.out.println();
 75         }
 76     }
 77 
 78 
 79     //方法:獲取所有數據
 80     public String[] toArray() {
 81         if (this.size == 0) {
 82             return null; // 沒有數據
 83         }
 84         this.foot = 0;       // 清零
 85         this.retData = new String[this.size];     // 開闢數組大小
 86         this.root.toArrayNode();
 87         return this.retData;
 88     }
 89 
 90 
 91     //獲取數據的長度
 92     public int size() {
 93         return this.size;
 94     }
 95 
 96     //判斷是否爲空鏈表
 97     public boolean isEmpty() {
 98         return this.size == 0;
 99     }
100 
101     //清空鏈表
102     public void clear() {
103         this.root = null;
104         this.size = 0;
105     }
106 
107 
108     //查詢數據是否存在
109     public boolean contains(String data) {      // 查找數據
110         // 根節點沒有數據,查找的也沒有數據
111         if (this.root == null || data == null) {
112             return false;        // 不須要進行查找了
113         }
114         return this.root.containsNode(data);        // 交給Node類處理
115     }
116 
117 
118     //方法:根據索引取得數據
119     public String get(int index) {
120         if (index > this.size) {         // 超過個數
121             return null;          // 返回null
122         }
123         this.foot = 0;       // 操做foot來定義腳標
124         return this.root.getNode(index);
125     }
126 
127 
128     //定義一個節點內部類(假設要保存的數據類型是字符串)
129     //比較好的作法是,將Node定義爲內部類,在這裏面去完成增刪、等功能,而後由LinkList去調用增、刪的功能
130     class Node {
131         private String data;
132         private Node next;  //next表示:下一個節點對象(單鏈表中)
133 
134         public Node(String data) {
135             this.data = data;
136         }
137 
138         //添加節點
139         public void addNode(Node newNode) {
140 
141             //下面這段用到了遞歸,須要反覆理解
142             if (this.next == null) {   // 遞歸的出口:若是當前節點以後沒有節點,說明我能夠在這個節點後面添加新節點
143                 this.next = newNode;   //添加新節點
144             } else {
145                 this.next.addNode(newNode);  //向下繼續判斷,直到當前節點以後沒有節點爲止
146 
147             }
148         }
149 
150 
151         //判斷節點是否存在
152         public boolean containsNode(String data) {      // 查找數據
153             if (data.equals(this.data)) {     // 與當前節點數據吻合
154                 return true;
155             } else {       // 與當前節點數據不吻合
156                 if (this.next != null) {   // 還有下一個節點
157                     return this.next.containsNode(data);
158                 } else {       // 沒有後續節點
159                     return false;        // 查找不到
160                 }
161             }
162         }
163 
164 
165         //刪除節點
166         public void removeNode(String data) {
167             if (this.next != null) {
168                 if (this.next.data.equals(data)) {
169                     this.next = this.next.next;
170                 } else {
171                     this.next.removeNode(data);
172                 }
173             }
174 
175         }
176 
177         //輸出全部節點
178         public void printNode() {
179             if (this.next != null) {
180                 System.out.print("-->" + this.next.data);
181                 this.next.printNode();
182             }
183         }
184 
185         //獲取所有數據
186         public void toArrayNode() {
187             LinkList.this.retData[LinkList.this.foot++] = this.data;
188             if (this.next != null) {
189                 this.next.toArrayNode();
190             }
191         }
192 
193 
194         //根據索引位置獲取數據
195         public String getNode(int index) {
196             if (LinkList.this.foot++ == index) {     // 當前索引爲查找數值
197                 return this.data;
198             } else {
199                 return this.next.getNode(index);
200             }
201         }
202 
203 
204     }
205 }

 

 

4、單鏈表的效率分析:

在單鏈表的任何位置上插入數據元素的機率相等時,在單鏈表中插入一個數據元素時比較數據元素的平均次數爲:

072cf138-eb31-4266-945f-1b5a110a2b16

刪除單鏈表的一個數據元素時比較數據元素的平均次數爲:

13f85f6f-ddc8-4a13-84cf-abed88fb356c

所以,單鏈表插入和刪除操做的時間複雜度均爲O(n)。另外,單鏈表讀取數據元素操做的時間複雜度也爲O(n)

二、順序表和單鏈表的比較:

順序表:

  優勢:主要優勢是支持隨機讀取,以及內存空間利用效率高;

  缺點:主要缺點是須要預先給出數組的最大數據元素個數,而這一般很難準確做到。當實際的數據元素個數超過了預先給出的個數,會發生異常。另外,順序表插入和刪除操做時須要移動較多的數據元素。

單鏈表:

  優勢:主要優勢是不須要預先給出數據元素的最大個數。另外,單鏈表插入和刪除操做時不須要移動數據元素;

  缺點:主要缺點是每一個結點中要有一個指針,所以單鏈表的空間利用率略低於順序表的。另外,單鏈表不支持隨機讀取,單鏈表取數據元素操做的時間複雜度爲O(n);而順序表支持隨機讀取,順序表取數據元素操做的時間複雜度爲O(1)。

相關文章
相關標籤/搜索