java双向链表解析实现双向链表的创建含代码

双向链表

一.双向链表

单向链表从头部开始我们的每一个节点指向后驱的节点。
此处为单向链表

单向链表

双向链表是相互指向前驱以及后驱的链表
前驱链表我们需要在我们的MyListCode内部类中在定义一个previous来接收每一个前驱的地址

想要删除任意节点可以直接通过访问下一个节点使其prev获取想要删除的上一个节点,然后将想要删除的上一个节点.next获取到被删除对象下一个节点的指向

这里我们可以模拟实现MyListCode类中的一些方法,入头插法、尾叉法、任意位置插入节点、指定元素删除含有该元素的第一个节点、指定元素删除含有该元素的所有节点等...

二.创建MyListCode类实现双向链表创建

java 复制代码
public class MyListNode implements IList {
  static class Node{
      public int val;
      //获取的后一个节点
      public Node next;
      //获取的前一个节点
      public Node prev;

      public Node(int val) {
          this.val = val;
      }
  }
  //始终在第一个节点
  public Node head;
  //指向最后一个节点
  public Node last;
  }

一.AddFirst创建(头插法)

这里当头部为null,没有头部和尾巴,我们将新节点作为头和尾,如果不为null,将每次产生的新节点对象放到头部,头部的pre与新节点相连,头部更新最新节点

java 复制代码
  @Override
    public void addFirst(int data) {
        Node node=new Node(data);
        if(this.head==null){
        //head指向头部,last指向尾巴
            this.head=node;
            this.last=node;
        }else{
        //不为空将新节点插入头部并将头部的pre置为新节点,最后更新头部位置
          node.next=this.head;
          this.head.prev=node;
          this.head=node;
        }
    }

二.AddLast创建(尾叉法)

这里考虑的是当head为空时,我们的头和尾巴都将获取新的节点,如果不为空,我们只需要移动last,将last的下一个节点获取到新的节点,新的节点pre指向last,最后last走向新节点,得到尾巴

java 复制代码
 @Override
    public void addLast(int data) {
        Node node=new Node(data);
        if(this.head==null){
            this.head=node;
            this.last=node;
        }else {
            this.last.next = node;
            node.prev = last;
            last=node;
        }
    }

三.size

从头部开始遍历或者尾部开始遍历

java 复制代码
 @Override
    public int size() {
        if(this.head==null){
            return 0;
        }
        Node cur=this.head;
        int count=0;
        while(cur!=null){
            count++;
            cur=cur.next;
        }
       return count;
    }
     @Override
    public void display() {
        Node cur=this.head;
        while(cur!=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }

四.remove(指定任意节点的首位删除)

首先判断如果头部值为空,说明没有节点,头部的下一个节点如果为key值则直接返回key(因为这里只是删除一个,所以不考虑多个带key的节点),然后遍历如果最后一个节点为key,它的下一个节点为null,则将双向节点置为null,如果不为null,就删除这个节点

java 复制代码
  @Override
    public void remove(int key) {
        if (this.head == null) {
            return;
        }
        if(this.head.val==key){
            //头节点为key将其更换为后驱节点,将后驱节点的prev置空
           this.head=this.head.next;
           this.head.prev=null;
           return;
        }
        Node cur=this.head.next;
        while(cur!=null){
            if(cur.val==key){
                //最后一个节点为key将前驱的下一项置空并将cur的pre置空
               if(cur.next==null){
                   cur.prev.next=null;
                   cur.prev=null;
                   return;
               }else{
                   //不是最后一个节点将前驱节的下一节点为当前节点下一项
                   //当前节点的下一项的前驱为当前项的前驱
                   cur.prev.next=cur.next;
                   cur.next.prev=cur.prev;
                   return;
               }
            }
            cur=cur.next;
        }
    }

五.removeAll(包含任意属性值的所有删除)

首先判断是否头部为空

判断最后一个last值是否时key,是key将双节点置空

然后判断key值,将key值在节点中删除

最后判断头节点是否为key,并将头节点置空

java 复制代码
@Override
    public void removeAll(int key) {
        if(this.head==null){
            return;
        }
        if(this.last.val==key) {
            //如果最后一项的值为key,将last前一项保留下来,最后赋值给last使其尾部更新
            Node pre=this.last.prev;
            this.last.prev.next = null;
            this.last.prev = null;
            this.last=pre;
        }
        Node cur=this.head.next;
        while(cur!=null){
            //cur的值如果为key清理该节点指向
            if(cur.val==key){
                cur.prev.next=cur.next;
                cur.next.prev=cur.prev;
            }
            cur=cur.next;
        }
        //最后判断head的值是否是key
        if(this.head.val==key){
            this.head=this.head.next;
        }
        //如果head有数据将head头的前节点置空
        if(this.head!=null){
            this.head.prev=null;
        }
    }

六.AddIndex(给任意位置添加一个节点)

首先判断头部是否为空

判断该坐标是否合法,如果该坐标在0或者在尾巴,则头插法和尾叉法

将给的坐标作为循环条件节点开始走,跳出循环后改节点位置就是要添加的位置

首先要把改节点的坐标向后移动一位,插入其中间

单链表的话将cur先指向后一个节点在指向前一个节点

java 复制代码
 @Override
    public void addIndex(int index,int data)throws RuntimeException {
        if(this.head==null){
            return;
        }
          try {
            if(index<0||index>size()){
                throw new RuntimeException("错误范围"+size());
            }
        }catch (RuntimeException e){
            e.printStackTrace();
        }
        if(index==0){
            addFirst(data);
            return;
        }
        if(index==size()){
            addLast(data);
            return;
        }
        Node node=new Node(data);
        Node cur=this.head;
        while(index>0){
            //出来后就是要插入的范围
            cur=cur.next;
            index--;
        }
        //在任意位置新增一个节点
        node.next=cur;
        node.prev=cur.prev;
        cur.prev=node;
        node.prev.next=node;
        return ;
    }

七.contains(无)

java 复制代码
 @Override
    public boolean contains(int key) {
        if(this.head==null){
            return false;
        }
        Node cur=this.head;
        while(cur!=null){
            if(cur.val==key){
                return true;
            }
            cur=cur.next;
        }
        return false;
    }

八.partition(区分链表的大小范围)

java 复制代码
    @Override
    public Node partition(Node node,int x) {
        if (node == null) {
            return null;
        }
        Node cur = node;
        Node min=null;
        Node minEnd=null;
        Node max=null;
        Node maxEnd=null;
        while (cur != null) {
            if(cur.val<x){
                if(min==null){
                    min=cur;
                    minEnd=cur;
                }else{
                    minEnd.next=cur;
                    minEnd=minEnd.next;
                }
            }else{
                if(max==null){
                    max=cur;
                    maxEnd=cur;
                }else{
                    maxEnd.next=cur;
                    maxEnd=maxEnd.next;
                }
            }
            cur = cur.next;
        }
        if(min==null){
            return max;
        }
        if(maxEnd!=null){
            maxEnd.next=null;
        }
        minEnd.next=max;
        return min;
    }
}

九.display(打印)

java 复制代码
@Override
    public void display() {
        Node cur=this.head;
        while(cur!=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }

接口类

java 复制代码
public interface IList {
    public void display();
    public int size();
    public void addFirst(int data);//新增一个节点放到头部
    public void addLast(int data);//新增一个节点放到尾部
    public void remove(int key);//删除第一个val值为key的节点
    public void removeAll(int key);//删除所有val值的节点
    public void addIndex(int index,int data);//在任意一个位置放入一个节点
    public boolean contains(int key);//是否包含key数值这个节点
    public MyListNode.Node partition(MyListNode.Node node,int x);//指定一个值,将数值小的放在前,将数值大的放在后
}

MyListNode整体代码

java 复制代码
import java.util.List;

public class MyListNode implements IList {
  static class Node{
      public int val;
      public Node next;
      public Node prev;

      public Node(int val) {
          this.val = val;
      }
  }
  //始终在第一个节点
  public Node head;
  //指向最后一个节点
  public Node last;

    @Override
    public void addFirst(int data) {
        Node node=new Node(data);
        if(this.head==null){
            this.head=node;
            this.last=node;
        }else{
          node.next=this.head;
          this.head.prev=node;
          this.head=node;
        }
    }

    @Override
    public void addLast(int data) {
        Node node=new Node(data);
        if(this.head==null){
            this.head=node;
            this.last=node;
        }else {
            this.last.next = node;
            node.prev = last;
            last=node;
        }
    }

    @Override
    public int size() {
        if(this.head==null){
            return 0;
        }
        Node cur=this.head;
        int count=0;
        while(cur!=null){
            count++;
            cur=cur.next;
        }
       return count;
    }
    public int size2(){
        if(this.head==null){
            return 0;
        }
        Node end=this.last;
        int count=0;
        while(end!=null){
            count++;
            end=end.prev;
        }
        return count;
    }
    @Override
    public void display() {
        Node cur=this.head;
        while(cur!=null){
            System.out.print(cur.val+" ");
            cur=cur.next;
        }
        System.out.println();
    }
    public void display2(){
        Node cur=this.last;
        while(cur!=null){
            System.out.print(cur.val+" ");
            cur=cur.prev;
        }
        System.out.println();
    }

    @Override
    public void remove(int key) {
        if (this.head == null) {
            return;
        }
        if(this.head.val==key){
            //头节点为key将其更换为后驱节点,将后驱节点的prev置空
           this.head=this.head.next;
           this.head.prev=null;
           return;
        }
        Node cur=this.head.next;
        while(cur!=null){
            if(cur.val==key){
                //最后一个节点为key将前驱的下一项置空并将cur的pre置空
               if(cur.next==null){
                   cur.prev.next=null;
                   cur.prev=null;
                   return;
               }else{
                   //不是最后一个节点将前驱节的下一节点为当前节点下一项
                   //当前节点的下一项的前驱为当前项的前驱
                   cur.prev.next=cur.next;
                   cur.next.prev=cur.prev;
                   return;
               }
            }
            cur=cur.next;
        }
    }

    @Override
    public void removeAll(int key) {
        if(this.head==null){
            return;
        }
        if(this.last.val==key) {
            //如果最后一项的值为key,将last前一项保留下来,最后赋值给last使其尾部更新
            Node pre=this.last.prev;
            this.last.prev.next = null;
            this.last.prev = null;
            this.last=pre;
        }
        Node cur=this.head.next;
        while(cur!=null){
            //cur的值如果为key清理该节点指向
            if(cur.val==key){
                cur.prev.next=cur.next;
                cur.next.prev=cur.prev;
            }
            cur=cur.next;
        }
        //最后判断head的值是否是key
        if(this.head.val==key){
            this.head=this.head.next;
        }
        //如果head有数据将head头的前节点置空
        if(this.head!=null){
            this.head.prev=null;
        }
    }

    @Override
    public void addIndex(int index,int data)throws RuntimeException {
        if(this.head==null){
            return;
        }
        if(index==0){
            addFirst(data);
            return;
        }
        if(index==size()){
            addLast(data);
            return;
        }
        try {
            if(index<0||index>size()){
                throw new RuntimeException("错误范围"+size());
            }
        }catch (RuntimeException e){
            e.printStackTrace();
        }
        Node node=new Node(data);
        Node cur=this.head;
        while(index>0){
            //出来后就是要插入的范围
            cur=cur.next;
            index--;
        }
        //在任意位置新增一个节点
        node.next=cur;
        node.prev=cur.prev;
        cur.prev=node;
        node.prev.next=node;
        return ;
    }

    @Override
    public boolean contains(int key) {
        if(this.head==null){
            return false;
        }
        Node cur=this.head;
        while(cur!=null){
            if(cur.val==key){
                return true;
            }
            cur=cur.next;
        }
        return false;
    }

    @Override
    public Node partition(Node node,int x) {
        if (node == null) {
            return null;
        }
        Node cur = node;
        Node min=null;
        Node minEnd=null;
        Node max=null;
        Node maxEnd=null;
        while (cur != null) {
            if(cur.val<x){
                if(min==null){
                    min=cur;
                    minEnd=cur;
                }else{
                    minEnd.next=cur;
                    minEnd=minEnd.next;
                }
            }else{
                if(max==null){
                    max=cur;
                    maxEnd=cur;
                }else{
                    maxEnd.next=cur;
                    maxEnd=maxEnd.next;
                }
            }
            cur = cur.next;
        }
        if(min==null){
            return max;
        }
        if(maxEnd!=null){
            maxEnd.next=null;
        }
        minEnd.next=max;
        return min;
    }
}

Test测试类代码

java 复制代码
public class Test {
    public static void main(String[] args) {
        MyListNode myListNode=new MyListNode();
        myListNode.addLast(3);
        myListNode.addLast(5);
        myListNode.addLast(7);
        myListNode.removeAll(6);
//        System.out.println(myListNode.last.val);
//        myListNode.display();
        myListNode.addIndex(1,9);
        System.out.println(myListNode.contains(3));
        myListNode.display();
        int len1 =  myListNode.size();
       int len2 =  myListNode.size();
        System.out.println(len1+"size");
        System.out.println(len2+"size1");
        MyListNode myListNode1=new MyListNode();
        myListNode1.addLast(3);
        myListNode1.addLast(3);
        myListNode1.addLast(8);
        myListNode1.addLast(9);
        myListNode1.addLast(19);
        myListNode1.addLast(3);
        myListNode1.display();
        myListNode1.display2();
        myListNode1.partition(myListNode1.head,5);
        myListNode1.display();
        myListNode1.display2();

    }
}

写的也有很多不好的地方,希望大佬们多多指点,谢谢!!祝大家开心快乐

相关推荐
拾荒的小海螺3 分钟前
JAVA:探索 EasyExcel 的技术指南
java·开发语言
Jakarta EE19 分钟前
正确使用primefaces的process和update
java·primefaces·jakarta ee
马剑威(威哥爱编程)27 分钟前
哇喔!20种单例模式的实现与变异总结
java·开发语言·单例模式
白-胖-子39 分钟前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
workflower40 分钟前
数据结构练习题和答案
数据结构·算法·链表·线性回归
好睡凯41 分钟前
c++写一个死锁并且自己解锁
开发语言·c++·算法
java—大象1 小时前
基于java+springboot+layui的流浪动物交流信息平台设计实现
java·开发语言·spring boot·layui·课程设计
yyqzjw1 小时前
【qt】控件篇(Enable|geometry)
开发语言·qt
csdn_kike1 小时前
QT Unknown module(s) in QT 以及maintenance tool的更详细用法(qt6.6.0)
开发语言·qt
JerryXZR1 小时前
JavaScript核心编程 - 原型链 作用域 与 执行上下文
开发语言·javascript·原型模式