LInkedList的模拟实现

在之前的文章笔者介绍了链表的实现:无头单向非循环链表的实现!感兴趣的各位老铁可以点进来看看:https://blog.csdn.net/weixin_64308540/article/details/128397961?spm=1001.2014.3001.5502

对于此篇博客,在一写出来,便引起了巨大反响!!那么后续来了!!今日,笔者来带领大家走进:LinkedList的模拟实现!(底层是双向链表结构)

LinkedList的底层是一个双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此,在任意位置插入或者删除元素时,不需要搬移元素,因此,效率比较高!!

我们来看一下实现的主要代码:

总体的方法:

public class MyLinkdeList {
    //无头双向链表的实现
    
    //头插法
    public void addFrist(int data){
    }
    
    //尾插法
    public void addLast(int data){
    }
    
    //任意位置插入,第一个数据节点的下标为0
    public void addIndex(int index,int data){
    }
    
    //查找关键字key是否在链表当中
    public boolean contains(int key){
    }
    
    //删除第一次出现关键字为key的节点
    public void remove(int key){
    }
    
    //删除所有值为key的节点
    public void removeAllkey(int key){
    }
    
    //得到链表的长度
    public int size(){
    }
    
    public void display(){
    }
    
    public void clear(){
    }
}

那么接下来就跟着笔者的思路,来实现这些方法吧!!

实现该方法之前的准备!每个节点所必须的东西!!

   static class ListNode{
        public int val;
        public ListNode prev;//前驱
        public ListNode next;//后继
        
        //重写构造方法
        public ListNode (int val){
            this.val=val;
        }
    }

在进行之前,我们还需要一个头节点和一个尾巴节点:

    public ListNode head;//链表的头部
    public ListNode last;//永远指向链表的最后一个节点

经过上述的准备,那么我们就可以安心实现上述的方法了!!

下面笔者便以下图的链表进行讲解:

    • 打印链表:
    //打印链表
    public void display(){
        ListNode cur=head;
        while (cur !=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }

很简单的一个代码,想必没有什么需要讲解的吧!!

2.得到链表的长度
    //得到链表的长度
    public int size(){
        int len=0;
        ListNode cur=head;
        while (cur != null){
            len++;
            cur=cur.next;
        }
        return len;
    }

这个就是在遍历链表的过程中,定义了一个len,每次进行++,从而得到链表的长度!

3.查找关键字key是否在链表当中
  //查找关键字key是否在链表当中
    public boolean contains(int key){
        ListNode cur=head;
        while (cur != null) {
            if (cur.val == key){//找到的情况下
                return true;
            }
            cur=cur.next;
        }
        return false;
    }

这个思路很简单,遍历一遍链表,当有val的值等于key的时候,直接return true即可!!如果链表遍历完毕,没有值等于key那么最后return false就行了!

4.头插法

时间复杂度为O(1)

头插法,顾名思义就是插到头节点之前呗!!

    //头插法
    public void addFrist(int data){
        //实列化一个新的节点
        ListNode node =new ListNode(data);
        if (head==null){
            head=node;
            last=node;
        }else {//先绑后面
            node.next=head;
            head.prev=node;
            head=node;//新的头节点
        }
    }

上述代码,我们可以从图中得出大致思路

5.尾插法

时间复杂度为O(1)

    //尾插法
    public void addLast(int data){
        //实列化一个新的节点
        ListNode node =new ListNode(data);
        if (head==null){
            head=node;
            last=node;
        }else {//先绑后面
            last.next=node;
            node.prev=last;
            last=node;
        }
    }

其实尾插法跟头插法的情况差不多!!很类似!!

6。任意位置插入,第一个数据节点的下标为0

对于想要插入数据的下标,我们首先需要判断其合法性!!然后在判断是否为头插法或者尾插法!!最后在考虑在链表内部的插入!!由于该链表是双向的链表,那么,我们可以找到index位置所对应的节点!

 //任意位置插入,第一个数据节点的下标为0
    public void addIndex(int index,int data){
        if(index <0 || index >size()){
            System.out.println("输入的位置不合法,请重新确定想要插入的位置!");
        }
        if (index==0){//头插法
            addFrist(data);
        }
        if (index==size()){//尾插法
            addLast(data);
        }
        //此时的index就是真正需要插入的地方了!
        //找到index位置的下标
        ListNode cur=findIndex(index);

        //实列化index位置处的data节点
        ListNode node=new ListNode(data);
        //开始插入
        node.next=cur;
        cur.prev.next=node;
        node.prev=cur.prev;
        cur.prev=node;
    }

    //找到index位置的下标
    public ListNode findIndex(int index){
        ListNode cur=head;
        while (index !=0){
            index--;
            cur=cur.next;
        }
        return cur;
    }

这个列子涉及很多分析地方!!所以需要珍惜一下!好好画图分析

7.删除第一次出现关键字为key的节点

对于该案列,我们需要找到想要删除的节点!若是头节点,我们应该怎么办??若是中间或者最后的节点,我们,又应该怎么办??这些都需要我们去认真思考!

 //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNode cur=head;
        while (cur !=null){
            if (cur.val==key){
                //删除的是头节点
                if (cur==head){
                    head=head.next;
                    //只有一个节点
                    if (head !=null){
                        head.prev=null;
                    }
                }else {
                    //中间  尾巴节点
                    cur.prev.next=cur.next;
                    //不是尾巴节点
                    if (cur.next !=null){
                        cur.next.prev=cur.prev;
                    }else {
                        //是尾巴节点
                        last=last.prev;
                    }
                }
            }
            return;
        }
        cur=cur.next;
    }

希望大家能够理性的分析!!

8.删除所有值为key的节点

对于这个案列,我们可以经过上面的简单改变一下就可以了!!

  //删除所有值为key的节点
    public void removeAllkey(int key){
        ListNode cur=head;
        while (cur !=null){
            if (cur.val==key){
                //删除的是头节点
                if (cur==head){
                    head=head.next;
                    //只有一个节点
                    if (head !=null){
                        head.prev=null;
                    }
                }else {
                    //中间  尾巴节点
                    cur.prev.next=cur.next;
                    //不是尾巴节点
                    if (cur.next !=null){
                        cur.next.prev=cur.prev;
                    }else {
                        //是尾巴节点
                        last=last.prev;
                    }
                }
            }
        }
        cur=cur.next;
    }
9.清除所有节点

第一开始笔者的想法也是,直接:head==null, last==null但是,感觉这样写虽然是这个道理,却总感觉有点儿不得劲,所以最后决定,遍历一遍链表,将每个节点的prev与last全部都置为null!!

  //清除所有节点
    public void clear(){
        while (head !=null){
            head.prev=null;
            head.next=null;
            head=head.next;
        }
        head=null;
        last=null;
    }

经过上面的全部代码,笔者可算是将:LinkedList的模拟实现!(底层是双向链表结构)给整理完毕了!!不容易,下面请看笔者所整理的全部代码吧!!

public class MyLinkdeList {
    //无头双向链表的实现

    static class ListNode{
        public int val;
        public ListNode prev;//前驱
        public ListNode next;//后继

        //重写构造方法
        public ListNode (int val){
            this.val=val;
        }
    }

    public ListNode head;//链表的头部
    public ListNode last;//永远指向链表的最后一个节点

    //头插法
    public void addFrist(int data){
        //实列化一个新的节点
        ListNode node =new ListNode(data);
        if (head==null){
            head=node;
            last=node;
        }else {//先绑后面
            node.next=head;
            head.prev=node;
            head=node;//新的头节点
        }
    }

    //尾插法
    public void addLast(int data){
        //实列化一个新的节点
        ListNode node =new ListNode(data);
        if (head==null){
            head=node;
            last=node;
        }else {//先绑后面
            last.next=node;
            node.prev=last;
            last=node;
        }
    }

    //任意位置插入,第一个数据节点的下标为0
    public void addIndex(int index,int data){
        if(index <0 || index >size()){
            System.out.println("输入的位置不合法,请重新确定想要插入的位置!");
        }
        if (index==0){//头插法
            addFrist(data);
        }
        if (index==size()){//尾插法
            addLast(data);
        }
        //此时的index就是真正需要插入的地方了!
        //找到index位置的下标
        ListNode cur=findIndex(index);

        //实列化index位置处的data节点
        ListNode node=new ListNode(data);
        //开始插入
        node.next=cur;
        cur.prev.next=node;
        node.prev=cur.prev;
        cur.prev=node;
    }

    //找到index位置的下标
    public ListNode findIndex(int index){
        ListNode cur=head;
        while (index !=0){
            index--;
            cur=cur.next;
        }
        return cur;
    }
    //查找关键字key是否在链表当中
    public boolean contains(int key){
        ListNode cur=head;
        while (cur != null) {
            if (cur.val == key){//找到的情况下
                return true;
            }
            cur=cur.next;
        }
        return false;
    }

    //删除第一次出现关键字为key的节点
    public void remove(int key){
        ListNode cur=head;
        while (cur !=null){
            if (cur.val==key){
                //删除的是头节点
                if (cur==head){
                    head=head.next;
                    //只有一个节点
                    if (head !=null){
                        head.prev=null;
                    }
                }else {
                    //中间  尾巴节点
                    cur.prev.next=cur.next;
                    //不是尾巴节点
                    if (cur.next !=null){
                        cur.next.prev=cur.prev;
                    }else {
                        //是尾巴节点
                        last=last.prev;
                    }
                }
            }
            return;
        }
        cur=cur.next;
    }

    //删除所有值为key的节点
    public void removeAllkey(int key){
        ListNode cur=head;
        while (cur !=null){
            if (cur.val==key){
                //删除的是头节点
                if (cur==head){
                    head=head.next;
                    //只有一个节点
                    if (head !=null){
                        head.prev=null;
                    }
                }else {
                    //中间  尾巴节点
                    cur.prev.next=cur.next;
                    //不是尾巴节点
                    if (cur.next !=null){
                        cur.next.prev=cur.prev;
                    }else {
                        //是尾巴节点
                        last=last.prev;
                    }
                }
            }
        }
        cur=cur.next;
    }

    //得到链表的长度
    public int size(){
        int len=0;
        ListNode cur=head;
        while (cur != null){
            len++;
            cur=cur.next;
        }
        return len;
    }

    //打印链表
    public void display(){
        ListNode cur=head;
        while (cur !=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }

    //清除所有节点
    public void clear(){
        while (head !=null){
            head.prev=null;
            head.next=null;
            head=head.next;
        }
        head=null;
        last=null;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_64308540/article/details/128615090