Java数据结构之双向链表实现

本文介绍了链表作为线性表的链式存储结构,对比了数组和链表的优缺点,并提供了Java代码实例,展示了如何创建链表类、节点类以及基本操作,如插入、删除和查找。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链表数据结构简介

部分设计思想参考 https://blog.youkuaiyun.com/qq_33697094/article/details/121544972

  • 线性表:也叫顺序表,是多个元素的有序序列,他的元素与索引一一对应。线性表包含两大存储结构:顺序存储结构与链式存储结构

  • 数组:是线性表的顺序存储结构,指用地址中一段顺序存储单元依次存储数据元素

  • 链表:是线性表的链式存储结构,他的内存是不连续,每一个元素的地址由上一个元素来存储。

数组与链表的底层数据结构决定了他们自身的特点以及使用场景

  • 数组在顺序存储单元存储元素,当我们要进行搜索时,它可以直接根据下标来返回需要搜索元素,但当我们进行增删时,则需要来移动大量元素。
  • 链表的存储结构是不连续的,除头尾节点,每一个元素需要存储他的数据值以及上一个元素的节点对象,下一个元素的节点对象。 这一数据结构特点导致我们如果想要搜索链表时,每一次都需要从头或尾开始遍历链表。但当我们增加元素时,只需要将上一元素尾指针指向新元素头节点,将下一元素头指针指向新元素尾节点即可。

代码实现

  • 废话少说直接上代码

首先创建链表类 以及内部节点类

//链表类
public class DoubleLinkDemo<T> {

    private NodeDemo head;//头指针
    private NodeDemo tail;//尾指针
    private int length;//链表长度

    public DoubleLinkDemo(){
        this.length = 0;
    }
    public DoubleLinkDemo(T data){
        NodeDemo<T> tNodeDemo = new NodeDemo<>(data);//新建节点对象
        this.head = tNodeDemo;//将该节点对象赋值为头节点
        this.tail = head;//因为该链表只有一个节点,所以头尾指针指向相同节点
        length++;//链表长度+1
    }
}
//节点类
class NodeDemo<T>{
    T data; //节点存储 数据
    NodeDemo pre; //记录上一节点对象
    NodeDemo next;//记录下一节点对象

    public NodeDemo(){
        this(null,null,null);
    }
    public NodeDemo(T data){
        this(data,null,null);
    }
    public NodeDemo(T data,NodeDemo pre,NodeDemo next){
        this.data = data;
        this.pre =pre;
        this.next = next;
    }

}

链表类添加基本方法

  • 链表类基本方法包括
//是否为空
   public boolean isEmpty(){
    }
//长度
    public int length(){
    }
//头节点插入元素
    public void insertHead(T data){
    }
//尾节点插入元素
    public void insertTail(T data){
    }
//指定索引新增元素
    public void insertNode(T data,int index){
    }
//指定索引删除元素
    public void deleteNode(int index){
    }
//指定索引获取元素 
    public Object get(int index){
    }
//索引获取node对象 (此方法内部使用 为private)
    private NodeDemo getNode(int index) {
    }

基本方法实现

public class DoubleLinkDemo<T> {

  private NodeDemo head;//头指针
  private NodeDemo tail;//尾指针
  private int length;//链表长度

  public DoubleLinkDemo(){
      this.length = 0;
  }
  public DoubleLinkDemo(T data){
      NodeDemo<T> tNodeDemo = new NodeDemo<>(data);
      this.head = tNodeDemo;//新节点赋值为头节点
      this.tail = head;//由于链表只有一个元素 所以头尾指针都指向同一元素
      length++;//链表长度+1
  }
  //是否为空
  public boolean isEmpty() {
      return head == null;
  }

  //长度
  public int length() {
      return length;
  }


  //头插入
  public void insertHead(T data) {
      //为空
      if (isEmpty()) {
          NodeDemo<T> firstNode = new NodeDemo<>(data);
          head = firstNode;
          tail = head;
      } else {
          //链表不为空 则顺序插入
          NodeDemo<T> tNodeDemo = new NodeDemo<>(data);
          head.pre = tNodeDemo;//当前头节点前指针指向新元素
          tNodeDemo.next = head;//新元素尾指针指向当前头节点
          head = tNodeDemo;//将新元素赋值为头节点
      }
      length++;
  }


  //尾插入节点
  public void insertTail(T data) {
      if (isEmpty()) {
          insertHead(data);
      } else {
          //不为空顺序插入
          NodeDemo<T> tNodeDemo = new NodeDemo<>(data);
          this.tail.next = tNodeDemo;//当前尾指针尾节点指向新增元素
          tNodeDemo.pre = this.tail;//新元素头节点指向尾节点
          tail = tNodeDemo; //新元素设置为尾节点
          length++;
      }
  }
  //索引获取node对象
  private NodeDemo getNode(int index) {
      if (index < 0 || index > length - 1) {
          throw new IndexOutOfBoundsException("数组越界");
      }
      NodeDemo<Object> targetNode = new NodeDemo<>();
      targetNode = head;
      int tar = 0;
      while (targetNode!= null) {
          if (tar++ == index) {
              return targetNode;
          }
          targetNode = targetNode.next;
      }
      return null;
  }
  //根据指定索引获取节点
  public Object get(int index){
      return getNode(index).data;
  }

  //根据指定索引添加数据
  public void insertNode(T data,int index){
      if(index<0||index>length-1){
          throw new IndexOutOfBoundsException("数组越绝");
      }else if(index==0){
          insertHead(data);
      }else if(index ==length-1){
          insertTail(data);
      }else {
          NodeDemo nowNode = getNode(index);
          NodeDemo preNode = getNode(index - 1);
          NodeDemo<T> insertNode = new NodeDemo<>(data);
          preNode.next = insertNode;//节点对象互相赋值
          insertNode.pre = preNode;
          insertNode.next = nowNode;
          nowNode.pre = insertNode;
      }
      length++;
  }

  //根据指定索引删除数据
  public void deleteNode(int index){
      if(index<0||index>length-1){
          throw new IndexOutOfBoundsException("数组越界");
      }else if(index==0){
          head.next.pre = null;
          head = head.next;
      }else if(index ==length-1){
          tail.pre.next = null;
          tail =tail.pre;
      }else {
          NodeDemo preNode = getNode(index - 1);
          NodeDemo nextNode = getNode(index + 1);
          preNode.next = nextNode;
          nextNode.pre = preNode;
      }
      length--;
  }

}

class NodeDemo<T>{
  T data;
  NodeDemo pre;
  NodeDemo next;

  public NodeDemo(){
      this(null,null,null);
  }

  public NodeDemo(T data){
      this(data,null,null);
  }
  public NodeDemo(T data,NodeDemo pre,NodeDemo next){
      this.data = data;
      this.pre =pre;
      this.next = next;

  }

}


测试链表

public class Test {

    public static void main(String[] args) {


        DoubleLinkDemo<Integer> doubleLinkDemo = new DoubleLinkDemo<>();
        System.out.println(doubleLinkDemo.isEmpty());
        doubleLinkDemo.insertTail(1);
        System.out.println(doubleLinkDemo.isEmpty());
        System.out.println(doubleLinkDemo.get(0));
        doubleLinkDemo.insertHead(0);
        System.out.println(doubleLinkDemo.get(0));
        doubleLinkDemo.insertTail(2);
        System.out.println(doubleLinkDemo.get(2));
        doubleLinkDemo.insertHead(123);
        System.out.println(doubleLinkDemo.get(0));
        doubleLinkDemo.insertTail(456);
        System.out.println(doubleLinkDemo.get(4));
        doubleLinkDemo.deleteNode(4);
        System.out.println(doubleLinkDemo.get(4));
        
    }
}


输出结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值