一 双向链表简介
双向链表的定义是,一个节点有两个方向,分别储存当前节点的前驱节点,和后续节点;双向链表的删除只需要指定前驱节点,或者后续节点就可以进行删除操作;但是缺点也很明显每次添加节点时都需要2个指向,额外增加了内存空间消耗;
二 双向链表的实现
3.1 定义链表节点
- 定义data存储数据,知识追寻者使用的时int类型,读者可以改为object类型;
- 定义前驱节点previous
- 定义后续节点next
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
public class DoubleNode {
private Integer data; private DoubleNode next; private DoubleNode previous; }
|
3.2 插入头节点
思路如下:
- 将新节点的前驱节点指向nul
- 新节点的后续节点指向表头
- 将表头的前驱节点指向新节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class DoubleList {
private DoubleNode head; public void addFirst(int data){ DoubleNode newNode = new DoubleNode(); newNode.setData(data); if (head==null){ head = newNode; }else { newNode.setNext(head); head.setPrevious(newNode); head = newNode; } }
public void displayNext(){ DoubleNode currentNode = head; while (currentNode!=null){ System.out.println(currentNode.getData()); currentNode = currentNode.getNext(); } } }
|
测试代码如下,往前插入数据,打印出来就是倒序
1 2 3 4 5 6 7
| public static void main(String[] args) { DoubleList doubleList = new DoubleList(); for (int i = 0; i <5 ; i++) { doubleList.addFirst(i); } doubleList.displayNext(); }
|
结果
3.3 插入尾节点
思路如下
- 表尾的后续节点指向新节点
- 新节点的前驱节点指向表尾
- 新节点的后续节点指向null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
public void addLast(int data){ DoubleNode newNode = new DoubleNode(); newNode.setData(data); if (head==null){ head = newNode; }else { DoubleNode currentNode = head; while (currentNode.getNext()!=null){ currentNode = currentNode.getNext(); } currentNode.setNext(newNode); newNode.setPrevious(currentNode); } }
|
测试代码如下,往表为插入数据,也就是顺序打印
1 2 3 4 5 6 7 8
| public static void main(String[] args) { DoubleList doubleList = new DoubleList(); for (int i = 0; i <5 ; i++) { doubleList.addLast(i); } doubleList.displayNext(); }
|
结果
3.4 获取链表长度
思路 :遍历链表,一个节点代表一个单位的长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public int length(){ int length = 0; DoubleNode currentNode = head; while (currentNode!=null){ length++; currentNode = currentNode.getNext(); } return length; }
|
3.5 指定位置插入节点
思路: 假设在BC直接插入新节点N
- B 节点的后续节点指向 N
- N 节点 的前驱节点指向 B
- N 节点的后续节点指向 C
- C 节点的前驱节点指向 N
重要的也就是要找到B节点的位置,转存C节点;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
|
public void add(int data, int index){ if (index<0 || index>length()){ System.out.println("非法索引"); return; } if (index==0){ addFirst(data); return; } if (index==length()){ addLast(data); return; } DoubleNode newNode = new DoubleNode(); newNode.setData(data); DoubleNode currentNode = head; int point = 0; while ((index-1)!= point){ currentNode = currentNode.getNext(); point++; } DoubleNode nextNode = currentNode.getNext(); currentNode.setNext(newNode); newNode.setPrevious(currentNode); newNode.setNext(nextNode); nextNode.setPrevious(newNode);
}
|
测试代码
1 2 3 4 5 6 7 8
| public static void main(String[] args) { DoubleList doubleList = new DoubleList(); for (int i = 0; i <5 ; i++) { doubleList.addLast(i); } doubleList.add(666,3); doubleList.displayNext(); }
|
结果
3.6 删除表头
思路如下
- 创建一个临时节点,存储表头的后续节点
- 将临时节点的前驱节点指向null
- 将临时节点赋值给表头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public void removeFirst(){ if (length()==0){ return; } if (length()==1){ head=null; return; } DoubleNode temNode = head.getNext(); temNode.setPrevious(null); head = temNode; }
|
测试代码
1 2 3 4 5 6 7 8
| public static void main(String[] args) { DoubleList doubleList = new DoubleList(); for (int i = 0; i <5 ; i++) { doubleList.addLast(i); } doubleList.removeFirst(); doubleList.displayNext(); }
|
结果
3.7 删除表尾
思路
- 找到表尾的前驱节点
- 将表尾的前驱节点的后续节点置为null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public void removeLast(){ if (length()==0){ return; } if (length()==1){ head=null; return; } DoubleNode previousNode = head; while (previousNode.getNext().getNext()!=null){ previousNode = previousNode.getNext(); } previousNode.setNext(null); }
|
测试代码
1 2 3 4 5 6 7 8 9
| public static void main(String[] args) { DoubleList doubleList = new DoubleList(); for (int i = 0; i <5 ; i++) { doubleList.addLast(i); } doubleList.removeLast(); doubleList.displayNext(); }
|
结果
3.8 删除指定节点
思路: 假设有BCD节点要删除B节点
- 将 B 节点的后续节点指向 D节点
- 将D节点前驱节点指向B节点
重要的也就是要找到B节点位置,转存D节点;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
|
public void remove(int index){ if (index<0 || index>=length()){ System.out.println("非法索引"); return; } if (index==0){ removeFirst(); return; } if (index==(length()-1)){ removeLast(); return; } DoubleNode previousNode = head; int point = 0; while ((index-1)!=point){ previousNode = previousNode.getNext(); point++; } DoubleNode nextNode = previousNode.getNext().getNext(); previousNode.setNext(nextNode); nextNode.setPrevious(previousNode);
}
|
测试代码
1 2 3 4 5 6 7 8 9
| public static void main(String[] args) { DoubleList doubleList = new DoubleList(); for (int i = 0; i <5 ; i++) { doubleList.addLast(i); } doubleList.remove(3); doubleList.displayNext(); }
|
结果