LinkedList

    • LinkedList的模拟实现(底层是一个双向链表)
    • LinkedList使用

LinkedList的模拟实现(底层是一个双向链表)

无头双向链表:有两个指针;一个指向前一个节点的地址;一个指向后一个节点的地址。
LinkedList_第1张图片
节点定义和链表初始化


    class ListNode{
        int val;
        ListNode prev;
        ListNode next;
        public ListNode(int val) {
            this.val = val;
        }
    }
        ListNode head;
        ListNode tail;
        
public void createList(){//初始化链表
ListNode ListNode1=new ListNode(1);
    ListNode ListNode2=new ListNode(1);
    ListNode ListNode3=new ListNode(1);
    ListNode ListNode4=new ListNode(1);
    ListNode ListNode5=new ListNode(1);
    ListNode ListNode6=new ListNode(1);
    ListNode1.next=ListNode2;
    ListNode2.next=ListNode3;
    ListNode3.next=ListNode4;
    ListNode4.next=ListNode5;
    ListNode5.next=ListNode6;
    //还要绑定prev
    ListNode6= ListNode5.prev;
    ListNode5= ListNode4.prev;
    ListNode4= ListNode3.prev;
    ListNode3= ListNode2.prev;
    ListNode2= ListNode1.prev;
 tail=ListNode6;//指向尾节点

this.head=ListNode1;
}

打印链表:

        public void myprintf(){
    ListNode cur=head;
    while(cur!=null){
        System.out.println(cur.val+"");
        cur=cur.next;
    }
        }

头插法:分两种情况,1:有多个节点;需要修改3个地方;2:没有节点的时候插入。tail是我们定义的尾巴,
1:head指向
2:原来头节点的null位置指向
3:插入的这个节点的next域
LinkedList_第2张图片

        //头插法
        public void addFirst(int data) {
            ListNode node = new ListNode(data);
            if (head == null) {//空链表的情况下头插
                head = node;
                tail = node;
            } else {//首先我们知道3个东西需要修改;改之前好好想一下这个东西还有没有作用;如果有你就不能先改;或者把值存起来
                node.next = head;
                head.prev = node;
                head = node;
            }

        }

尾插法:和头插差不多;也是分两种情况;1:空链表;2:有多个节点情况;需要修改3个地方

     //尾插法
        public void addLast(int data){
            ListNode node = new ListNode(data);
            if (head == null) {//空链表的情况下尾插,情况一样
                head = node;
                tail = node;

            } else {

            //这时候我们的指向尾的指针就有用了
                tail.next=node;
             node.prev=tail.prev;
             tail=node;//尾插后,尾得更新一下,这个容易忘
            }
          }

任意位置插入:分空链表(单独处理)和多个节点(需要先遍历找到位置;需要修改4个指向)。我们需要判断一下插入的位置合法不合法

     //任意位置插入,第一个数据节点为0号下标
        public boolean addIndex(int index,int data){
     //index位置合法性
            ListNode node = new ListNode(data);
            if (head == null) {//空链表的情况下尾插,情况一样
                head = node;
                tail = node;
            return true;
            }
            if(index<0||index>size()){
                System.out.println("插入的位置不合法");
                return false;

            }
            if(index==0){//头插
                addFirst( data);
                return true;
            }
            if(index==size()) {//尾插
                addLast (data);
                return true;
            }
            ListNode cur1=select( index);
            node.next=cur1;//前驱节点我不知道怎么表示
            //prev指向前驱的地址,前驱地址又可以.prev/.next
            //cur1.prev.next       cur1.prev找到前一个的地址,
            cur1.prev.next=node;
            node.prev=cur1.prev;
            cur1.prev=node;
            return true;
        }

找位置:

        public ListNode select(int index){
    ListNode cur=head;
    while(index>0){
        cur=cur.next;

    }
    return cur;
        }

删除第一次出现值为key节点:
我们先不考虑头尾:先考虑中间情况

前驱的next等于当前的next,跳过中间
在这里插入图片描述

cur.next前驱等于cur前驱
在这里插入图片描述
LinkedList_第3张图片
算上头尾情况的:整体代码
LinkedList_第4张图片
上述代码还不够:只有一个节点的情况lhead.prev;没有前驱;空指针异常;(都没有前驱;上述代码还要找前驱);在第7行代码还得再套一层娃
LinkedList_第5张图片

清除函数:
LinkedList_第6张图片
为什么单向链表清除能直接head=null;而双向链表不能head=null、tail=null缺不行?
理论上单向链表也是要将所有的节点都置为null;双向链表为了更好1及时释放内存空间;就是正常情况下head=null和tail=null它的中间节点也是会被垃圾回收器回收的

LinkedList使用

LinkedList_第7张图片

在这里插入图片描述

带参数构造方法,实现这个接口的都可以传进来;顺序表实现了这个接口,所以把顺序表传过去也行,链表,顺序表add都是默认尾插的。
LinkedList_第8张图片
foreach遍历:
LinkedList_第9张图片
迭代器遍历:
LinkedList_第10张图片
反向遍历
LinkedList_第11张图片
ArrysList和LinkedList区别:
增删改查上、储存上呢:
LinkedList_第12张图片

你可能感兴趣的:(数据结构,Linkedlist)