文章目錄
一、鏈表特點以及原理
查詢慢,增刪快。
這個分爲兩種情況,在頭尾增加,查詢、和在中間增刪,查詢;
在頭尾進行:
在頭尾進行增刪,直接在存儲頭尾對象的first、last添加上新加的元素即可(效率極高);
在頭尾進行查詢,因爲內部優化,大於一半從後往前查詢,效率方面也是可以的。
在中間進行:
在中間查詢,需要把位數走一遍,也就是需要查詢索引5的內容,就要創建(5-1)次的對象,時間及其慢。
在中間刪除,要把上面查詢的步驟走一遍以後,在把指定的元素刪除,再把其前後兩個對象(鏈表),連接起來。
二、單個實現原理解析
1、添加元素add方法(添加內容)
分爲添加第一個元素和其它元素兩種:
第一個元素: 存儲的首個元素(first)和末尾元素(last)都是當前設置的元素;
其它元素: 先將兩個元素進行綁定、設置最後一個元素的next爲null,存儲的最後一個元素爲當前元素;
2、toString方法
利用StringBuilder創建對象,從first元素遞歸獲取每一個存儲的對象(element)值,存儲進StringBuilder中。
3、get方法(根據索引)
調用7、檢測索引,調用4、獲取指定對象,並從對象中獲取元素(element)的值;
4、獲取指定索引的對象(索引)
分兩種情況,索引大於有效長度一半(size),從後側開始檢索,不滿足從左側;
根據當前對象存儲的下一個對象的內容,進行遞歸判斷,直到找到自己想要的次數對象爲止;
5、remove方法(刪除指定索引位置元素)
調用4、獲取指定對象,分情況進行刪除(1、開頭;2、中間位置;3、末尾位置),長度減一(size–)
開頭: 根據當前元素獲取後一個元素對象,設置存儲的首個元素(first)爲後一個元素;
中間: 獲取當前元素前後兩個元素對象,並把這兩個元素進行連接;
末尾: 根據當前元素獲取前一個元素對象,設置存儲的末尾元素(last)爲前一個元素;
6、add方法(根據索引添加到指定位置)
調用4、獲取指定對象,分情況進行添加(1、開頭;2、中間位置;3、末尾位置),長度加一(size++)
開頭: 創建兩個元素連接,設置存儲的首個元素(first)爲當前對象;
中間: 獲取當前元素前一個元素對象,將前一個元素與當前元素連接,將當前元素與後一個元素連接;
末尾: 創建兩個元素連接,設置存儲的末尾元素(last)爲當前對象;
7、索引檢測
判斷索引的數組內容進行判斷,不滿足則拋出運行時異常(RuntimeException)
三、完整增加步驟
1、創建基礎結構,添加add、toString方法
Node存儲元素對象
public class Node {
Node privious; //上一個節點
Node next; //下一個節點
Object element; //元素數據
public Node(Node privious, Node next, Object element) {
this.privious = privious;
this.next = next;
this.element = element;
}
public Node(Object element) {
this.element = element;
}
}
MyLinkedList工具類
public class MyLinkedList {
private Node first;
private Node last;
// 1、添加元素add方法
public void add(Object obj) {
Node node = new Node(obj);
if (first == null) {
first = node;
last = node;
} else {
// 元素的開頭爲上一個元素對象(最後一個對象)
node.privious = last;
// 元素的最後爲null
node.next = null;
// 上一個元素設置爲後一個對象
last.next = node;
// 設置最後元素爲現在的對象
last = node;
}
}
// 2、toString方法
public String toString() {
StringBuilder sb = new StringBuilder("[");
Node temp = first;
while (temp != null) {
sb.append(temp.element + ",");
temp = temp.next;
}
sb.setCharAt(sb.length() - 1, ']');
return sb.toString();
}
調用測試:
public static void main(String[] args) {
MyLinkedList list = new MyLinkedList();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
String s = list.toString();
System.out.println(s);
}
}
難點解析:
是設置新創建的元素的對象裏面的,前一個元素地址(privious)和後一個元素地址(next)
//元素的開頭爲上一個元素對象(最後一個對象)
node.privious = last;
//元素的最後爲null
node.next = null;
是設置創建的上一個元素裏面的,後一個元素地址(next)的值,其中last存儲的上一個元素對象的地址值;
//上一個元素設置爲後一個對象
last.next = node;
//設置最後元素爲現在的對象
last = node;
2、增加get方法
增加size變量,並添加size的增加方法
private int size;
// 1、添加元素add方法
public void add(Object obj) {
Node node = new Node(obj);
if (first == null) {
first = node;
last = node;
} else {
// 元素的開頭爲上一個元素對象(最後一個對象)
node.privious = last;
// 元素的最後爲null
node.next = null;
// 上一個元素設置爲後一個對象
last.next = node;
// 設置最後元素爲現在的對象
last = node;
}
size++;
}
增加get方法
// 3、get方法
public Object get(int index) {
if (index < 0 || index > size - 1) {
throw new RuntimeException("索引數字不合法" + index);
}
Node temp = null;
if (index <= (size >> 1)) { //索引位置靠近與開頭位置
temp = first;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
} else { //索引位置靠近於末尾位置
temp = last;
for (int i = size - 1; i > index; i--) {
temp = temp.privious;
}
}
return temp.element;
}
3、get方法優化、增加remove方法
get方法優化
// 3、get方法
public Object get(int index) {
if (index < 0 || index > size - 1) {
throw new RuntimeException("索引數字不合法" + index);
}
//調用封裝的getNode方法獲取指定索引位置對象
Node temp = getNode(index);
return temp != null ? temp.element : null;
}
// 4、封裝的獲取指定索引的對象
public Node getNode(int index) {
Node temp = null;
if (index <= (size >> 1)) { //索引位置靠近與開頭位置
temp = first;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
} else { //索引位置靠近於末尾位置
temp = last;
for (int i = size - 1; i > index; i--) {
temp = temp.privious;
}
}
return temp;
}
增加remove方法
// 5、remove方法
public void remove(int index) {
if (index < 0 || index > size - 1) {
throw new RuntimeException("索引數字不合法" + index);
}
Node temp = getNode(index);
if (temp != null) {
Node before = temp.privious;
Node after = temp.next;
if (before != null) {
before.next = after;
}
if (after != null) {
after.privious = before;
}
// 被刪除的元素是第一個元素時
if (index == 0) {
first = after;
}
// 被刪除的元素時最後一個元素時
if (size == index - 1) {
last = before;
}
size--;
}
}
4、根據索引添加元素
// 6、add方法
public void add(int index,Object obj){
if (index<0||index>size-1){
throw new RuntimeException("請輸入指定範圍索引 "+index);
}
Node newNode = new Node(obj);
Node temp = getNode(index);
if (temp!=null){
Node before = temp.privious;
// 1、添加的元素在第一個時
if (index==0){
newNode.next=temp;
temp.privious=newNode;
first=newNode;
}
// 2、添加的元素在最後一個時
if (index==size-1){
newNode.privious=temp;
temp.next=newNode;
last=newNode;
size++;
return;
}
// 3、添加的元素在普通位置時
if (before!=null){
// 新建元素與前一個創建連接
before.next=newNode;
newNode.privious=before;
// 新建元素與後一個創建連接
newNode.next=temp;
temp.privious=newNode;
}
size++;
}
}
5、增加索引檢測、泛型
索引檢測:
// 7、索引檢測
private void checkRange(int index) {
if (index < 0 || index > size - 1) {
throw new RuntimeException("索引數字不合法: " + index);
}
}
泛型:
public class MyLinkedList<E> {
private Node first;
private Node last;
private int size;
// 1、添加元素add方法
public void add(E element) {
Node node = new Node(element);
if (first == null) {
first = node;
last = node;
} else {
// 元素的開頭爲上一個元素對象(最後一個對象)
node.privious = last;
// 元素的最後爲null
node.next = null;
// 上一個元素設置爲後一個對象
last.next = node;
// 設置最後元素爲現在的對象
last = node;
}
size++;
}
四、完整版代碼
public class MyLinkedList<E> {
private Node first; //存儲第一個元素對象
private Node last; //存儲最後一個元素對象
private int size; //有效的索引長度(存有值的位數)
// 1、添加元素add方法(添加內容)
public void add(E element) {
Node node = new Node(element);
if (first == null) {
first = node;
last = node;
} else {
// 元素的開頭爲上一個元素對象(最後一個對象)
node.privious = last;
// 元素的最後爲null
node.next = null;
// 上一個元素設置爲後一個對象
last.next = node;
// 設置最後元素爲現在的對象
last = node;
}
size++;
}
// 2、toString方法
public String toString() {
StringBuilder sb = new StringBuilder("[");
Node temp = first;
while (temp != null) {
sb.append(temp.element + ",");
temp = temp.next;
}
sb.setCharAt(sb.length() - 1, ']');
return sb.toString();
}
// 3、get方法(根據索引)
public E get(int index) {
// 檢測索引
checkRange(index);
//調用封裝的getNode方法獲取指定索引位置對象
Node temp = getNode(index);
return temp != null ? (E)temp.element : null;
}
// 4、獲取指定索引的對象
private Node getNode(int index) {
// 檢測索引
checkRange(index);
Node temp = null;
if (index <= (size >> 1)) { //索引位置靠近與開頭位置
temp = first;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
} else { //索引位置靠近於末尾位置
temp = last;
for (int i = size - 1; i > index; i--) {
temp = temp.privious;
}
}
return temp;
}
// 5、remove方法(刪除指定索引位置元素)
public void remove(int index) {
// 檢測索引
checkRange(index);
Node temp = getNode(index);
if (temp != null) {
Node before = temp.privious;
Node after = temp.next;
if (before != null) {
before.next = after;
}
if (after != null) {
after.privious = before;
}
// 被刪除的元素是第一個元素時
if (index == 0) {
first = after;
}
// 被刪除的元素時最後一個元素時
if (size == index - 1) {
last = before;
}
size--;
}
}
// 6、add方法(根據索引添加到指定位置)
public void add(int index, E element) {
// 檢測索引
checkRange(index);
Node newNode = new Node(element);
Node temp = getNode(index);
if (temp != null) {
Node before = temp.privious;
// 1、添加的元素在第一個時
if (index == 0) {
newNode.next = temp;
temp.privious = newNode;
first = newNode;
}
// 2、添加的元素在最後一個時
if (index == size - 1) {
newNode.privious = temp;
temp.next = newNode;
last = newNode;
size++;
return;
}
// 3、添加的元素在普通位置時
if (before != null) {
// 新建元素與前一個創建連接
before.next = newNode;
newNode.privious = before;
// 新建元素與後一個創建連接
newNode.next = temp;
temp.privious = newNode;
}
size++;
}
}
// 7、索引檢測
private void checkRange(int index) {
if (index < 0 || index > size - 1) {
throw new RuntimeException("索引數字不合法: " + index);
}
}
}