一、實現get方法
1、一般思維實現思路
- 1)、將物件的值放入一箇中間變數中。
- 2)、遍歷索引值,將中間量的下一個元素賦值給中間量。
- 3)、返回中間量中的元素值。
- 4)、示意圖
- get(2),傳入角標,迴圈兩次獲取到[1]元素,如圖.
2、實現思路實現
/**
* 最基本的寫法
*
* <p>按照角標迴圈元素,獲取最後一個元素的值</p>
*
* <p>存在問題:效率不高</p>
*
* @param index 元素的角標
* @return 角標代表的元素
*/
public Object get(int index) {
Node node = firstNode;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node.elements;
}
/**
* @author liuyangos8888
*/
public class TestGet {
public static void main(String[] args) {
testGetBase();
}
private static void testGetBase() {
MyGetLinkedList001 myGetLinkedList001 = new MyGetLinkedList001();
myGetLinkedList001.add("A");
myGetLinkedList001.add("B");
myGetLinkedList001.add("C");
myGetLinkedList001.add("D");
myGetLinkedList001.add("E");
myGetLinkedList001.add("F");
System.out.println(myGetLinkedList001.get(4));
}
}
3、思路缺少的條件
// 判斷索引範圍
if (index < 0 || index > size - 1) {
throw new RuntimeException("索引不合法!" + index);
}
- 2)、查詢方式的優化問題(獲取第888個索引時候,效率極低,建議使用折半查詢)
/**
* 優化版,提高查詢效率,折半判斷
*
* @param index 索引角標
* @return 索引對應的值
*/
public Object get1(int index) {
// 判斷索引範圍
if (index < 0 || index > size - 1) {
throw new RuntimeException("索引不合法!" + index);
}
Node node = null;
// size>>1 除以2
if (index <= (size >> 1)) {
node = firstNode;
for (int i = 0; i < index; i++) {
node = node.next;
}
} else {
node = lastNode;
for (int i = size - 1; i > index; i--) {
node = node.previous;
}
}
return node.elements;
}
- 3)、發現的其他問題(採用此方式get時候,add需要size++)
// 不做size++,在get判斷範圍的時候就會出現錯誤
public void add(Object o) {
Node node = new Node(o);
if (firstNode == null) {
firstNode = node;
} else {
node.previous = lastNode;
node.next = null;
lastNode.next = node;
}
lastNode = node;
size++;
}
二、實現remove方法
1、一般思維實現思路
- 1)、把前一個元素的next元素,變為next.next元素
- 2)、把最後一個元素的previous元素,變為previous.previous元素
- 3)、size值減少操作
- 4)、示意圖
- 有A、B、C三個節點,以連結串列形式儲存(如上圖)
- 現在要刪除節點B,A、C不變(如上圖)
- 方法就是截斷A、C跟B的連線,A和C重新建立新的連線,JAVA的實現方式就是,用物件覆蓋B節點的值。
2、實現思路實現
/**
* 根據索引,刪除陣列中元素
*
* @param index 索引角標
*/
public void remove(int index) {
Node temp = getNode(index);
if (temp != null) {
Node up = temp.previous;
Node down = temp.next;
if (up != null) {
up.next = down;
}
if (down != null) {
down.previous = up;
}
size--;
}
}
/**
* @author liuyangos8888
*/
public class TestRemove {
public static void main(String[] args) {
MyGetLinkedList002 myGetLinkedList002 = new MyGetLinkedList002();
myGetLinkedList002.add("A");
myGetLinkedList002.add("B");
myGetLinkedList002.add("C");
myGetLinkedList002.add("D");
myGetLinkedList002.add("E");
myGetLinkedList002.add("F");
System.out.println(myGetLinkedList002);
myGetLinkedList002.remove(3);
System.out.println(myGetLinkedList002);
myGetLinkedList002.remove(0);
System.out.println(myGetLinkedList002);
myGetLinkedList002.remove(3);
System.out.println(myGetLinkedList002);
}
}
3、思路缺少的條件
// 判斷索引範圍
if (index < 0 || index > size - 1) {
throw new RuntimeException("索引不合法!" + index);
}
// 刪除第一個元素的時候
if (index == 0) {
firstNode = down;
}
// 刪除最後一個元素的時候
if (index == size - 1) {
lastNode = up;
}
三、實現insert(add)方法
1、一般思維實現思路
- 1)、獲取索引的元素值,得到元素的前一個節點
- 2)、把前節點的後一個節點設定為加入的節點
- 3)、新節點的前一個節點設定為索引值節點的前節點
- 4)、前一個節點的後一個節點是索引值節點
- 5)、索引值節點的前一個節點是新節點
- 6)、示意圖
- 有A、B、C三個節點,以連結串列形式儲存,現在要新增D節點,到連結串列中.
- 切斷A、B的節點連線,A和D,D和B重新建立連線,生成新的連結串列
2、實現思路實現
/**
* 插入一個元素在指定位置
*
* @param index 指定位置索引
* @param o 插入的元素
*/
public void insert(int index, Object o) {
Node newNode = new Node(o);
// 判斷範圍
checkRound(index);
Node temp = getNode(index);
if (temp != null) {
// 第一個元素和最後一個元素的時候
if (index == 0 || index == size - 1) {
temp.elements = newNode.elements;
} else {
Node up = temp.previous;
isNull(up == null, "前一個元素為空");
up.next = newNode;
newNode.previous = up;
newNode.next = temp;
temp.previous = newNode;
}
}
}
/**
* 插入一個元素在指定位置
*
* @param index 指定位置索引
* @param o 插入的元素
*/
public void insert1(int index, Object o) {
Node newNode = new Node(o);
// 判斷範圍
checkRound(index);
Node temp = getNode(index);
if (temp != null) {
// 第一個元素和最後一個元素的時候
if (index == 0) {
firstNode = newNode;
newNode.next = temp.next;
} else if (index == size - 1) {
Node up = temp.previous;
isNull(up == null, "前一個元素為空");
up.next = newNode;
newNode.previous = up;
} else {
Node up = temp.previous;
isNull(up == null, "前一個元素為空");
up.next = newNode;
newNode.previous = up;
newNode.next = temp;
temp.previous = newNode;
}
}
}
public class TestInsert {
public static void main(String[] args) {
MyInsertLinkedList003 myInsertLinkedList003 = new MyInsertLinkedList003();
myInsertLinkedList003.add("A");
myInsertLinkedList003.add("B");
myInsertLinkedList003.add("C");
myInsertLinkedList003.add("D");
myInsertLinkedList003.add("E");
myInsertLinkedList003.add("F");
myInsertLinkedList003.insert1(1,"G");
System.out.println(myInsertLinkedList003);
}
}
3、思路缺少的條件
private void checkRound(int index) {
// 判斷索引範圍
isNull(index < 0 || index > size - 1, "索引不合法!" + index);
}
/**
* 判斷空指標問題
*
* @param b 判斷條件
* @param string 丟擲異常的原因
*/
private void isNull(boolean b, String string) {
if (b) {
throw new RuntimeException(string);
}
}
if (temp != null) {
// 第一個元素和最後一個元素的時候
if (index == 0) {
firstNode = newNode;
newNode.next = temp.next;
} else if (index == size - 1) {
Node up = temp.previous;
isNull(up == null, "前一個元素為空");
up.next = newNode;
newNode.previous = up;
} else {
Node up = temp.previous;
isNull(up == null, "前一個元素為空");
up.next = newNode;
newNode.previous = up;
newNode.next = temp;
temp.previous = newNode;
}
}
四、實現泛型和全部程式碼
package com.synway.test.collections.version3.finallist;
import com.synway.test.collections.version3.basesimple.Node;
/**
* 最終手寫版,新增泛型
*
* @author liuyangos8888
*/
public class MyLinkedListFinal<T> {
/**
* 第一個節點
*/
private Node firstNode;
/**
* 最後一個節點
*/
private Node lastNode;
/**
* 連結串列大小
*/
private int size;
/**
* 新增節點到陣列中
*
* @param o 節點資料
*/
public void add(T o) {
Node node = new Node(o);
if (firstNode == null) {
firstNode = node;
} else {
node.previous = lastNode;
node.next = null;
lastNode.next = node;
}
lastNode = node;
size++;
}
/**
* 根據索引,刪除陣列中元素
*
* @param index 索引角標
*/
public void remove(int index) {
checkRound(index);
Node temp = getNode(index);
if (temp != null) {
Node up = temp.previous;
Node down = temp.next;
if (up != null) {
up.next = down;
}
if (down != null) {
down.previous = up;
}
// 刪除第一個元素的時候
if (index == 0) {
firstNode = down;
}
// 刪除最後一個元素的時候
if (index == size - 1) {
lastNode = up;
}
size--;
}
}
/**
* 插入一個元素在指定位置
*
* @param index 指定位置索引
* @param o 插入的元素
*/
public void insert(int index, T o) {
Node newNode = new Node(o);
// 判斷範圍
checkRound(index);
Node temp = getNode(index);
if (temp != null) {
// 第一個元素和最後一個元素的時候
if (index == 0) {
firstNode = newNode;
newNode.next = temp.next;
} else if (index == size - 1) {
Node up = temp.previous;
isNull(up == null, "前一個元素為空");
up.next = newNode;
newNode.previous = up;
} else {
Node up = temp.previous;
isNull(up == null, "前一個元素為空");
up.next = newNode;
newNode.previous = up;
newNode.next = temp;
temp.previous = newNode;
}
}
}
/**
* 優化版,提高查詢效率,折半判斷
*
* @param index 索引角標
* @return 索引對應的值
*/
public T get(int index) {
checkRound(index);
Node node = getNode(index);
return node != null ? (T) node.elements : null;
}
/**
* 根據角標,獲取節點
*
* @param index 傳入角標
* @return 獲取節點
*/
private Node getNode(int index) {
Node node;
// size>>1 除以2
if (index <= (size >> 1)) {
node = firstNode;
for (int i = 0; i < index; i++) {
node = node.next;
}
} else {
node = lastNode;
for (int i = size - 1; i > index; i--) {
node = node.previous;
}
}
return node;
}
/**
* 稽核傳入的角標範圍是否越界
*
* @param index 傳入角標
*/
private void checkRound(int index) {
// 判斷索引範圍
isNull(index < 0 || index > size - 1, "索引不合法!" + index);
}
/**
* 判斷空指標問題
*
* @param b 判斷條件
* @param string 丟擲異常的原因
*/
private void isNull(boolean b, String string) {
if (b) {
throw new RuntimeException(string);
}
}
/**
* 獲取陣列中元素
*
* @return 元素陣列
*/
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("[");
Node temp = firstNode;
while (temp != null) {
stringBuilder.append(temp.elements).append(",");
temp = temp.next;
}
stringBuilder.setCharAt(stringBuilder.length() - 1, ']');
return stringBuilder.toString();
}
}