【數據結構】:單鏈表 循環鏈表 雙向循環鏈表 雙鏈表

單鏈表

image.png
若是是null,就說明後面沒有節點了,若是不是null就說明後面要鏈接節點
image.png
每一個節點包含2部分,數據域,和一個指向下一個節點引用的指針next
data域--存放結點值的數據域
next域--存放結點的直接後繼的地址的指針域(鏈域)
鏈表經過每一個結點的鏈域將線性表的n個結點按其邏輯順序連接在一塊兒的,每一個結點只有一個鏈域的鏈表稱爲單鏈表(Single Linked List)。
單鏈表
image.png
顯示全部節點信息
image.pngspa

  • 頭部插入節點
  • 若是鏈表沒有頭結點,新結點直接成爲頭結點;不然新結點的next直接指向當前頭結點,並讓新結點成爲新的頭結點。
    image.png
/**
* 添加結點至鏈表頭部
*
* @param value
*/
public void addHeadNode(T value) {
   Node newNode = new Node(value);
   //頭結點不存在,新結點成爲頭結點
   if (head == null) {
       head = newNode;
       return;
   }
   //新結點next直接指向當前頭結點
   newNode.next = head;
   //新結點成爲新的頭結點
   head = newNode;
}
  • 尾部插入節點
  • 若是鏈表沒有頭結點,新結點直接成爲頭結點;不然須要先找到鏈表當前的尾結點,並將新結點插入到鏈表尾部。
    image.png
/**
* 添加結點至鏈表尾部
*
* @param value
*/
public void addTailNode(T value) {
   Node newNode = new Node(value);
   //頭結點不存在,新結點成爲頭結點
   if (head == null) {
       head = newNode;
       return;
   }
   //找到最後一個結點
   Node last = head;
   while (last.next != null) {
       last = last.next;
   }
   //新結點插入到鏈表尾部
   last.next = newNode;
}
  • 指定位置插入節點
  • 先判斷插入位置爲頭尾兩端的狀況,即index == 0插入到頭部,index == size()插入到尾部;若是插入位置不是頭尾兩端,則先找出當前index位置的結點cur以及前一個結點 pre,而後cur成爲新結點的下一個結點,新結點成爲pre的後一個結點,這樣就成功插入到index位置。
    image.png
/**
 * 結點插入至指定位置
 *
 * @param value 結點數據
 * @param index 插入位置
 */
public void addNodeAtIndex(T value, int index) {
    if (index < 0 || index > size()) { //注意index是能夠等於size()的
        throw new IndexOutOfBoundsException("IndexOutOfBoundsException");
    }
    if (index == 0) {  //插入到頭部
        addHeadNode(value);//前面定義的方法
    } else if (index == size()) {  //插入到尾部
        addTailNode(value);//前面定義的方法
    } else {  //插到某個中間位置
        Node newNode = new Node(value);
        int position = 0;
        Node cur = head;  //標記當前結點
        Node pre = null;  //記錄前置結點
        while (cur != null) {
            if (position == index) {
                newNode.next = cur;
                pre.next = newNode;
                return;
            }
            pre = cur;
            cur = cur.next;
            position++;
        }
    }
}

插入一個節點作當前節點的下一個節點
image.png.net

  • 指定位置刪除節點
  • 找出當前index位置的結點cur以及前一個結點 pre,pre.next直接指向cur.next便可刪除cur結點。
/**
 * 刪除指定位置的結點
 *
 * @param index 指定位置
 */
public void deleteNodeAtIndex(int index) {
    if (index < 0 || index > size() - 1) {
        throw new IndexOutOfBoundsException("IndexOutOfBoundsException");
    }
    if (index == 0) { //刪除頭
        head = head.next;
        return;
    }
    int position = 0;  //記錄當前位置
    Node cur = head;  //標記當前結點
    Node pre = null;  //記錄前置結點
    while (cur != null) {
        if (position == index) {
            pre.next = cur.next;
            cur.next = null;  //斷開cur與鏈表的鏈接
            return;
        }
        pre = cur;
        cur = cur.next;
        position++;
    }

}
  • 刪除下一個節點
    image.png
  • 鏈表反轉
  • 在鏈表遍歷的過程當中將指針順序置換,即每遍歷一次鏈表就讓cur.next指向pre,最後一個結點成爲新的頭結點。反轉以後指針入下圖紅線所示。
/**
 * 鏈表反轉
 */
public void reverse() {
    Node cur = head; //標記當前結點
    Node pre = null; //標記當前結點的前一個結點
    Node temp;
    while (cur != null) {
        //保存當前結點的下一個結點
        temp = cur.next;
        //cur.next指向pre,指針順序置換
        cur.next = pre;
        //pre、cur繼續後移
        pre = cur;
        cur = temp;
    }
    //最後一個結點變成新的頭結點
    head = pre;
}
  • 求倒數第k個結點
  • 倒數第k個結點就是第size() - k + 1個結點,cur結點向後移動size() - k次就是倒數第k個結點。
/**
 * 倒數第k個結點
 *
 * @param k
 * @return
 */
public T getLastK(int k) {
    if (k < 0 || k > size()) { //注意index是能夠等於size()的
        throw new IndexOutOfBoundsException("IndexOutOfBoundsException");
    }
    Node cur = head;
    for (int i = 1; i < size() - k + 1; i++) {
        cur = cur.next;
    }
    return cur.value;
}

循環鏈表

image.png
循環鏈表
image.png指針

雙鏈表

image.png
image.png
雙向鏈表code

循環雙向列表

循環雙向列表一開始的pre和next都是本身
image.png
image.png
image.png
image.pngblog