定义:
双向链表是链表的一种,链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。优势在于插入数据,查找数据较麻烦,想要弄懂双向链表就要先弄懂单向链表,首先单项链表是一种数据结构,它除尾节点外每个节点中只有尾地址,并且每个尾地址指向下一个节点,只能单项遍历,就是只能找到后继,无法找到前驱,也就是只能前进。
而双向链表除头节点和尾节点外,每个节点都有首地址与尾地址,并且首地址会指向上个节点,尾地址会指向下一个节点,能前后(两头)遍历,跟单项链表相比,打破了单项链表的单项遍历的局限性,能提升查找的效率,但是增加删除节点复杂,需要多分配存储空间。
LinkedList底层源码实现
1.构造节点类
public class Node {
//为节点构造属性
//首地址
Node prev;
//存放节点的数据
Object val;
//尾地址
Node next;
//构造方法使下一节点的首地址指向上一节点,尾地址指向下一节点,并存放下一节点的数据。
public Node(Node p, Object o, Node n) {
this.prev = p;
this.val = o;
this.next = n;
}
}
2.add源码实现
public class MyListAdd {
//建构造一个头节点
Node first;
//再构造一个尾结点
Node last;
//定义链表的长度
int size;
public void add(Object item){
//last先指向l节点(就是说现在l就是尾结点)
Node l=last;
//new一个newNode链接在l后
Node newNode=new Node (l,item,null);
//让last指向newNode节点(此时newNode为尾节点)
last=newNode;
//判断如果l节点为空节点,那newNode就是头结点
//如果l非空,说明newNode前已有节点l,l的尾地址就指向了newNode(last尾结点)
if (l==null){
first=newNode;
}else{
l.next=newNode;
}
//在链表增加一个节点后扩容
size++;
}
}
3.remove源码实现
public class MyListRemove {
//建构造一个头节点
Node first;
//再构造一个尾结点
Node last;
//定义链表的长度
int size;
//实现按下标删除数据
//先构造方法通过用户输入的下标来进行查找节点
public Node node(int index){
//如果下标位于链表长度的前一半就从头节点开始找,并返回查找到的值;
//如果下标位于链表长度的后半部分就从尾结点开始找,返回查找值。
if (index<size/2){
Node temp=first;
for(int i=0;i<index;i++){
temp=temp.next;
}
return temp;
}else{
Node temp=last;
for (int i=size-1;i>index;i--){
temp=temp.prev;
}
return temp;
}
}
//按下标删除
public void remove (int index){
//找到需要删除的节点
Node delNode=node(index);
//删除头节点,让头节点与下一节点断开
if (delNode==first){
first=first.next;
first.prev=null;
}//删除尾节点,使尾结点与上一节点断开
else if (delNode==last){
last=last.prev;
last.next=null;
}//删除中间节点,让该节点的上一节点的尾地址指向该节点的下一节点
//让该节点的下一节点的首地址指向该节点上一节点
else{
delNode.prev.next=delNode.next;
delNode.next.prev=delNode.prev;
}
//删除节点后链表长度减一
size--;
}
}
4.建个Demo类进入调试
public class Demo {
public static void main(String[] args) {
MyList ml = new MyList();
ml.add(123);
ml.add(456);
ml.add("hello");
ml.add("kkk");
ml.add("123123");
ml.add("8797");
ml.remove(4);
}
}