LinkedList-双向链表实现

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

无头双向链表:有两个指针;一个指向前一个节点的地址;一个指向后一个节点的地址。
在这里插入图片描述

节点定义和链表初始化


    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(2);
    ListNode ListNode3=new ListNode(3);
    ListNode ListNode4=new ListNode(4);
    ListNode ListNode5=new ListNode(5);
    ListNode ListNode6=new ListNode(6);
    ListNode1.next=ListNode2;
    ListNode2.next=ListNode3;
    ListNode3.next=ListNode4;
    ListNode4.next=ListNode5;
    ListNode5.next=ListNode6;
    //还要绑定prev
     ListNode1.prev=null;
     ListNode2.prev=ListNode1;
     ListNode3.prev=ListNode2;
     ListNode4.prev=ListNode3;
     ListNode5.prev=ListNode4;
     ListNode6.prev= ListNode5;
     
     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:原来头节点的前驱位置指向
3:插入的这个节点的next指向
在这里插入图片描述

    //头插法
    public void addFirst(int data) {
        ListNode listNode=new ListNode(data);
        if(head==null){//修改的时候就想象这个节点插入位置情况;有哪些地方需要改(修改无非就几个东西:head、tail、前一个节点的prev、next。后一个节点的prev、next。插入节点的prev、next);注意:空链表、只有一个节点情况
            head=listNode;
            tail=listNode;
            listNode.next=null;//虽然不赋值都是null;为了可读性
            listNode.prev=null;
        }else {
            listNode.next=head;
            head.prev=listNode;
            head=listNode;
            listNode.prev=null;

        }
    }
尾插法

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

   //尾插法
    public void addLast(int data){
        ListNode listNode=new ListNode(data);
        if(head==null){
            head=listNode;
            tail=listNode;
            listNode.next=null;
            listNode.prev=null;
        }else {
            tail.next=listNode;
            listNode.prev=tail;
            tail=listNode;
        }
    }
index位置插入

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

中间位置插入ListNode分析:
在这里插入图片描述

//index位置插入
    public boolean addIndex(int index,int data){
        if(index<0||index>size()){
            System.out.println("插入的位置不合法");
            return false;
        }
        if(index==0||head==null){//头插
            addFirst( data);
            return true;
        }
        if(index==size()) {//尾插
            addLast (data);
            return true;
        }
        ListNode listNode=new ListNode(data);//中间插入;先找到index位置;然后插入这个节点的位置
        ListNode indexListNode=select(index);//找到index

        listNode.prev=indexListNode.prev;
        listNode.next=indexListNode;
        indexListNode.prev.next=listNode;//前一个节点的后继等于插入节点
        indexListNode.prev=listNode;
        return true;



    }


    //链表长度
    public int size(){
        ListNode cur=head;
        int length=0;
        while(cur!=null){
            length++;
            cur=cur.next;
        }
        System.out.println(length);
        return length;
    }

    //查找index位置
    public ListNode select(int index){
        ListNode cur=head;
        while(index>0){
            cur=cur.next;
            index--;
        }
        System.out.println(cur.val);
        return cur;
    }

删除第一个值为key节点

遍历去找;找到了;判断一下这个节点是不是头、是不是尾;因为删除头、尾、中间都是不同的。虽然代码能少量复用;但是学习阶段;重点在于可读性。

  //删除第一次出现key值节点
    public void remove(int key){
        ListNode cur=head;
        while (cur!=null){
          if(cur.val==key){
              if(cur==head){
                  head.next.prev=null;
                  head=head.next;
                  break;
              }else if(cur==tail){
                  tail.prev.next=null;
                  tail=tail.prev;
                  break;
              }else {
                  //我应该要找到删除节点的前一个;然后直接跳过这个节点就是删除了。就把前一个节点的next跳过这个;后一个节点的prev往前跳过这个节点
                  cur.next.prev=cur.prev;
                  cur.prev.next=cur.next;
                  break;
              }
          }
          cur=cur.next;
        }
    }

清除链表

  public void clear(){
       ListNode cur=head;
       while (cur!=null){
           ListNode curNext=cur.next;
           cur.next=null;
           cur.prev=null;
           cur=curNext;
       }
       head=null;
       tail=null;
    }

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

LinkedList常用方法

在这里插入图片描述

带参数构造方法,实现这个接口的都可以传进来;顺序表实现了这个接口,所以把顺序表传过去也行
在这里插入图片描述

ArrysList和LinkedList区别

增删改查上、储存上呢:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瞭望~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值