手写LinkedList的实现,彻底搞清楚什么是链表?

本文介绍了LinkedList数据结构的特点,包括基于链表的存储方式、高效率的插入和删除操作以及低效的遍历。通过图示和简单代码展示了如何手写实现LinkedList的add、get和remove方法,帮助理解链表的工作原理。对于面试中的LinkedList题目,本文提供了一种直观的学习方法。

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

面试官Q1:可以手写一个LinkedList的简单实现吗?

当听见手写一个具体类的实现的时候,是不是有点懵逼,其实在大多数面试中,要手写几率还是很小的,对一些工作了好几年的老油条,一般面试只是让你简单介绍一下LinkedList数据结构,但是对于应届毕业生,不管是单向链表还是双向链表,考到要手写的几率还是蛮大的,所以扎实的基本功还是必须的。废话不多说了,我们先来总结一下LinkedList有哪些特点:

  • LinkedList是基于链表实现;
  • 其存储数据放在节点里面;
  • 插入和删除操作效率高,无需遍历数据,打断节点连接,重新连接即可;
  • 遍历数据效率低,无法通过索引定位;

数据结构

LinkedList底层的数据结构是基于双向循环链表的,每个节点分为头部、尾部以及业务数据,前一个节点尾部指向后一个节点的头部,后一节点的头部指向前一个节点的尾部,对应的就是下面图示:
在这里插入图片描述
但是对于头结点和尾节点比较特殊,头结点的头部没有上一个结点,从上图可知并没有指向,尾节点的尾部也没有指向下一个结点。
所以,如上我们可以知道链表是由一个一个节点构成,我们是不是可以定义一个结点类Node,如下:

1//用来表示一个节点
 2public class Node {
 3     Node previous;//头部,用来指向上一个节点
 4     Object obj;
 5     Node next;//尾部,用来指向下一个节点
 6
 7    public Node() {
 8    }
 9
10    public Node(Node previous, Object obj, Node next) {
11        super();
12        this.previous = previous;
13        this.obj = obj;
14        this.next = next;
15    }
16
17    public Node getPrevious() {
18        return previous;
19    }
20
21    public void setPrevious(Node previous) {
22        this.previous = previous;
23    }
24
25    public Object getObj() {
26        return obj;
27    }
28
29    public void setObj(Object obj) {
30        this.obj = obj;
31    }
32
33    public Node getNext() {
34        return next;
35    }
36
37    public void setNext(Node next) {
38        this.next = next;
39    }   
40}

添加数据add

既然结点已经有了,我们是不是考虑将这些结点一个个串起来,形成我们想要的链表结构,定义add方法如下:

 1public class MyLinkedList {
 2    private Node first;//定义一个头结点
 3    private Node last;//定义一个尾节点
 4    private int size;
 5
 6        //添加业务数据
 7    public void add(Object obj){
 8                //new一个结点出来
 9        Node n = new Node();
10            //如果是一个新的链表,没有任何数据
11        if(first==null){
12        //从图示可知,这个时候新增的结点既是头结点也是尾节点,头结点的头部没有任何指向所以设置为null,
13       //尾节点的尾部没有任何指向,所以也为null,真正的业务数据放在obj属性里面
14            n.setPrevious(null);
15            n.setObj(obj);
16            n.setNext(null);
17
18            first = n;
19            last = n;
20        }else{
21            //这个时候我们添加下一个结点,直接往last节点后增加新的节点
22            n.setPrevious(last);
23            n.setObj(obj);
24            n.setNext(null);
25            //当前结点尾部要指向新添加进来的结点
26            last.setNext(n);
27            //此时,新加进来的结点就变成了尾节点
28            last = n;
29        }
30        size++;
31    }
32
33     public int size(){
34        return size;
35    }
36}

用一张图,描述上述add的过程,结点就这样被串起来了
在这里插入图片描述

我们简单测试一下,add方法是否成功。

查询数据get

当我们add完数据后,如果想获取某个下标对应的结点,这个时候又该如何操作呢?LinkedList不像ArrayList可以直接通过索引下标定位到具体的数据,链表是一个个结点组成,当我们想要获取第三个结点时,需要一个个的去遍历,从头开始找直到找到为止
在这里插入图片描述

对应代码如下:

 1public Object get(int index){   //2
 2        // 0 1 2 3 4
 3        Node temp = node(index);
 4        if(temp!=null){
 5            return temp.obj;
 6        }
 7        return null;
 8    }
 9
10    public Node node(int index){
11        Node temp = null;
12        if(first!=null){
13            temp = first;
14            for(int i=0;i<index;i++){
15                temp = temp.next;
16            }
17        }
18        return temp;
19    }

可想而知,如果这个链表数据量很大,这种方式去遍历效率该有多低,当然这个不是我们这节的重点,笔者只是想通过简单的方式,来阐述一下链表的实现原理。

删除数据remove

查询完数据后,现在我们来删数据,链表删数据效率是很高的,为什么效率高,看完下面这张图你就理解了:
在这里插入图片描述

只需要打断原有的指向关系,重新连接指向,就可以删除指定位置处的数据,非常的高效。如果是ArrayList删除数据,上面2节点,将会被后面的3节点取代,它要移位,后面的所有节点都要跟着移位,所以ArrayList效率比较低。
用一段代码,描述上述过程:

 1public void remove(int index){
 2        Node temp = node(index);
 3
 4        if(temp!=null){
 5            Node up = temp.previous;
 6            Node down = temp.next;
 7            up.next = down;
 8            down.previous = up;
 9            size--;
10        }
11
12    }

指定位置添加数据

如果在指定位置添加一条数据,又该如何实现呢?

 1public void add(int index,Object obj){
 2        Node temp = node(index);
 3
 4        Node newNode = new Node();
 5        newNode.obj = obj;
 6
 7        if(temp!=null){
 8            Node up = temp.previous;
 9            up.next = newNode;
10            newNode.previous = up;
11
12            newNode.next = temp;
13            temp.previous = newNode;
14
15            size++;
16        }
17    }

跟上面删除节点一个原理,打断原有指向,重新指向,数据就插入进去了。如下图:
在这里插入图片描述

本文通过简单的代码以及图示,讲解了LinkedList的实现原理,当然JDK源码里面的LinkedList实现方式可没有这个这么简单,大家如果有兴趣可以去看一下源码,源码提供了各种使用方式。如果面试遇到手写LinkedList实现,你会了吗?

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值