JAVA数据结构-04 双向链表
双向链表的结构与单向链表相同,包含数据域和指针域.区别在于双向链表同时包含指向下一个节点的next指针和指向上一个节点的pre指针.
- 单向链表只能从前往后进行遍历,双向链表可以从前和后两个方向进行遍历
- 单向链表不能自我删除,需要靠辅助节点进行,所以单向链表的删除需要找到前一个节点.而双向链表可以进行自我删除.
双向链表的结构
数据节点:
//每一个数据节点就是一个music对象
class Music2{
public int no;
public String name;
public Music2 next; //指向下一个节点
public Music2 pre;
public Music2(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Music2{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
链表结构:
class DoubleLinkedList{
private Music2 head = new Music2(0,"");
public int getLength(){
int length = 0;
Music2 temp = head;
while(temp.next != null){
length ++;
temp = temp.next;
}
return length;
}
}
双向链表的操作
遍历:
- 双向链表的遍历与单向链表相同.
public void showList(){
if(head.next == null){
System.out.println("链表为空");
return;
}
Music2 temp = head.next;
while(temp != null){
System.out.println(temp);
temp = temp.next;
}
}
添加(到链表尾部):
- 遍历到链表的尾部;
- 修改待插入数据结点的前后指针,完成添加
//添加到尾部
public void add(Music2 musicNode){
Music2 temp = head;
while(temp.next != null){
temp = temp.next;
}
temp.next = musicNode;
musicNode.pre = temp;
}
插入:(根据下标index,数据节点从1开始)
-
遍历到待插入的index节点前一个位置,使temp指针指向index-1;
-
先将待插入链表的前后指针指向index-1和index位置(没破坏原有链表结构)
-
musicNode.next = temp.next; musicNode.pre = temp;
-
-
修改index-1位置的节点,使其next指针指向待插入节点;修改index位置的节点,使其pre指针指向待插入节点
-
temp.next.pre = musicNode; temp.next = musicNode;
-
public void insertIndex(Music2 musicNode,int index){
int length = getLength();
if(index > length+1 || index <0){
System.out.println("index错误");
return ;
}
Music2 temp = head;
while ((--index) >0){
temp = temp.next;
} //指向index位前一个位置
if(temp.next == null){ //temp是最后一个节点,执行add操作
temp.next = musicNode;
musicNode.pre = temp;
}else {
musicNode.next = temp.next;
musicNode.pre = temp;
temp.next.pre = musicNode;
temp.next = musicNode;
}
}
删除:
- 因为双向链表可以进行自我删除,所以不需要找到待删除节点的前一个节点位置,直接找到待删除位置即可.
public Music2 delete(int index){
int length = getLength();
if(index > length || index <0){
System.out.println("index错误");
return new Music2(-1,"error");
}
Music2 temp = head;
while (index >0){
temp = temp.next;
index --;
} //指向index位,双向链表可以自我删除,不需要定位到前一个位置
temp.pre.next = temp.next;
if(temp.next != null){ //只有当待删除节点是最后一个节点时不需要执行, 否则会报空指针异常
temp.next.pre = temp.pre;
}
return temp;
}
测试完整代码:
public class DoubleLinkedListDemo {
public static void main(String args[]){
DoubleLinkedList list = new DoubleLinkedList();
list.add(new Music2(1,"再见杰克"));
list.add(new Music2(4,"西湖"));
list.showList();
System.out.println(list.getLength());
list.insertIndex(new Music2(2,"给你唱首歌"),3);
list.showList();
System.out.println(list.delete(3));
list.showList();
}
}
class DoubleLinkedList{
private Music2 head = new Music2(0,"");
public int getLength(){
int length = 0;
Music2 temp = head;
while(temp.next != null){
length ++;
temp = temp.next;
}
return length;
}
public void showList(){
if(head.next == null){
System.out.println("链表为空");
return;
}
Music2 temp = head.next;
while(temp != null){
System.out.println(temp);
temp = temp.next;
}
}
//添加到尾部
public void add(Music2 musicNode){
Music2 temp = head;
while(temp.next != null){
temp = temp.next;
}
temp.next = musicNode;
musicNode.pre = temp;
}
public void insertIndex(Music2 musicNode,int index){
int length = getLength();
if(index > length+1 || index <0){
System.out.println("index错误");
return ;
}
Music2 temp = head;
while ((--index) >0){
temp = temp.next;
} //指向index位前一个位置
if(temp.next == null){
temp.next = musicNode;
musicNode.pre = temp;
}else {
musicNode.next = temp.next;
musicNode.pre = temp;
temp.next.pre = musicNode;
temp.next = musicNode;
}
}
public Music2 delete(int index){
int length = getLength();
if(index > length || index <0){
System.out.println("index错误");
return new Music2(-1,"error");
}
Music2 temp = head;
while (index >0){
temp = temp.next;
index --;
} //指向index位,双向链表可以自我删除,不需要定位到前一个位置
temp.pre.next = temp.next;
if(temp.next != null){ //只有当待删除节点是最后一个节点时不需要执行, 否则会报空指针异常
temp.next.pre = temp.pre;
}
return temp;
}
}
//每一个数据节点就是一个music对象
class Music2{
public int no;
public String name;
public Music2 next; //指向下一个节点
public Music2 pre;
public Music2(int no, String name) {
this.no = no;
this.name = name;
}
@Override
public String toString() {
return "Music2{" +
"no=" + no +
", name='" + name + '\'' +
'}';
}
}
JAVA 中 LinkedList 类源码解析
LinkedList内置的数据节点:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
LinkedList数据结构的实现:
- LinkedList包含三个字段:
- size记录双向链表的长度
- first记录双向链表的头指针
- last记录双向链表的尾指针
transient int size = 0;
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;