Java實現鏈表(個人理解鏈表的小例子)


1、單鏈表和數組的區別

數組:數組的存儲空間是連續的,需要事先申請空間確定大小,通過下標查找數據,所以查找速度快,但是增加和刪除速度慢
鏈表:離散存儲,不需要事先確定大小,通過頭指針加遍歷查找數據,查找數據慢,但是增加和刪除速度快

【舉例】

把內存空間看成一個教室,同學代表數據

【數組】

  • 申請空間

int[] seat = new int[5]表示我從教室(內存空間)申請第一排座位(數組),座位按1,2,3.....的順序標記,seat[1]表示坐在第一個位置的同學(數據),同學只能坐第一排。

  • 存儲數據

    • 來了第一個同學(1)他坐在了第1個位置(int[0] = 1),

    • 來了第二個同學(4) 他屁事多,他要做第6個位置(int[5] = 4),此時老師罵人了,那里不讓做(數組越界異常),無奈,第二個同學選擇了第4個位置(int[3] = 4)

    • 接下來五個同學都坐滿了

  • 查找

查找數據就不用說了吧,對號入座,老師很快就可以按座位號(下標)叫第幾個同學回答問題

  • 刪除

這個就有點麻煩了,第二個同學不認真,老師叫他滾出去,這時候座位號應該減少一個,那么第三個同學就要往左移一格(int[1] = int[2]),后面依次往左移一格,最后int[4]空出來了,所以應該把最后一個座位還給教室(歸還給內存),所以說這個還是比較麻煩的(ps:我是按照c語言思想講這里的,只學過Java的同學可能難以接受)需要移動座位,很麻煩

【鏈表】

  • 申請空間

    鏈表不需要事先申請空間

  • 添加數據(這里講的是有頭節點的鏈表,方便寫代碼)

    • 老師先讓班長(頭節點)找好位置(可用內存),老師只知道班長的座位號(地址),這時候班長找好了位置,告訴了老師,老師對班長說:吩咐下去,叫每一個同學記好在他們后一個進教室的同學的座位(地址)

    • 第一個同學M進來,按照自己的心情找了個空座位(可用內存),班長(頭節點)記錄了他的座位

    • 第二同學N進來,也按照自己的心情找了個空座位(可用內存),第一個同學記錄了第二個同學的座位

      ......以此類推

  • 查找數據(每個同學只知道他們下一個進來的同學)

    • 老師對班長(頭節點)說:點名,第3個進來的同學回答問題

    • 班長說:我后面進來的是同學M,找到了M

    • M說:我后面進來的是同學N,找到了N

    • N說:我后面進來的同學是X,找到了第三個進來的同學X

    • 老師說:就是你了,同學X回答問題

  • 刪除數據

    • 第2個進教室的同學調皮搗蛋,老師讓他滾出去
    • 重復查找數據步驟,班長——>M——>N(找到第二進來的同學)
    • 讓N滾動,此時,在M后進入的同學就是X了,只要記住座位號就可以了
    • 不要移動座位,很方便

  • 插入數據

    • 同學N改過自新了,重新申請做在第二個位置
    • 重復查找步驟,班長——>M(找到第一個進來的同學)
    • M記住他的下一個同學是N
    • N記住他的下一個同學是X
    • 不要移動座位,很方便

2、代碼實現

數據結構這種東西,太玄學了,我當初學的c語言版本,學了好久就是不明白,突然有一天就腦袋就開竅了,估計是菩薩保佑

現在來用java代碼實現

1、定義鏈表

public class SingleLinkedList<T>{
    //記錄鏈表長度
    private int size;
    //頭節點,不存數據,方便實現增刪代碼的
    private Node head;
    /**
     * 成員內部類,節點類,相當於例子中的同學和座位號的集合題
     * 我覺得這個類不應該暴露給外部
     */
    private class Node{
        private Node next;
        private T t;
        Node(Node next,T t){
            this.next = next;
            this.t = t;
        }
        Node(T t){
            this(null,t);
        }
        Node(){
            Node next = null;
            t = null;
        }
    }
    //鏈表構造方法
    public SingleLinkedList(){
        //初始化頭節點,不存數據,方便實現增刪代碼的
        this.head = new Node();
        this.size = 0;
    }
    
    /**
     * 此處省略了方法,單獨拿出來給大家講解
     * .........
     */
}

2、獲取長度

//獲取長度
public int getSize(){
    return size;
}

3、添加節點

 //添加節點
 public void add(T t){
     Node newNode = new Node(t);
     Node temp = this.head;
     while(temp.next != null){
         temp = temp.next;
     }
     temp.next = newNode;
     size++;
 }

4、插入節點

//插入節點,先判斷節點是否合法
public void insert(T t,int index){
    if(index <= 0 || index > this.size){
        throw new RuntimeException("index參數不合法");
    }
    Node newNode = new Node(t);
    Node temp = this.head;
    //要明白到底循環幾次
    for (int i = 1; i < index; i++) {
        temp = temp.next;
    }
    //注意順序
    newNode.next = temp.next;
    temp.next = newNode;
    size++;
}

5、取節點數據

//取節點數據
public T getValue(int index){
    if(index <= 0 || index > this.size){
        throw new RuntimeException("index參數不合法");
    }
    Node temp = this.head;
    //要明白到底循環幾次
    for (int i = 0; i < index; i++) {
        temp = temp.next;
    }
    return temp.t;
}

6、刪除節點

//刪除節點
public void delete(int index){
    if(index <= 0 || index > this.size){
        throw new RuntimeException("index參數不合法");
    }
    Node temp = this.head;
    //要明白到底循環幾次
    for (int i = 1; i < index; i++) {
        temp = temp.next;
    }
    temp.next = temp.next.next;
    //java垃圾回收機制gc自動回收內存
    size--;
}

7、遍歷

//遍歷
public void showData(){
    Node temp = this.head;
    //要明白到底循環幾次
    for (int i = 0; i < this.size; i++) {
        temp = temp.next;
        System.out.print("["+temp.t+"]-->");
    }
}

【總結】

個人代碼水平有限,僅作參考


免責聲明!

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



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