【数据结构】单向链表的原理及实现

简介: 【数据结构】单向链表的原理及实现

1.什么是单链表

链表里的数据是以节点的方式表示的,每一个结点的组成是由:元素+指针来组成的,元素就是存储数据里的存储单元,指针就是用来连接每一个结点的地址数据。这个以结点的序列来表示线性表被称作为单链表。

单链表是一种链式储存结构。在物理储存单元不连续,非顺序。

  • 结点里的数据域是用来存储数据元素的
  • 指针是用于指向下一个具有相同结构的结点
  • 因为只有一个指针结点,故而被称为单链表


b0d1eb6241c849b9be7e8852611fc35e.jpg

2.单链表的实现

末尾增加元素 void add(T data)
指定下标增加元素 void add(int index,T data)
删除指定下标元素 void delete(int index)
获取指定下标的元素 T get(int index)
修改指定下标的元素 void update(int index,T data)
遍历输出所有元素 void show()
获取链表的长度 int length()

(1)定义数据节点实体

a646a0461e9e4bcf9815f0265b5fcac4.jpg

(2)向链表末尾增加元素

0b35b5677bf24aafbec6489e246868b8.jpg

(3)指定下标向链表增加元素

0b35b5677bf24aafbec6489e246868b8.jpg

(4)删除指定下标元素的数据

51a9538df2a94734a763546468b72f9d.jpg

(5)修改指定下标的元素

a4684099578a489286b54f7ecf10ad5c.jpg

(6)获取指定下表的元素

5840669ddd5b4f27a1a279c468eb4d33.jpg

(7)循环遍历输出

b4918c6cb8744654a74eefc8dd744bc7.jpg

(8)获取当前有效的元素个数

c83388267fbb4c4e8567db334f1dbb1a.jpg

3.单链表测试

(1)整体代码实现

public class SingleLinkedList<T> {
    /**
     * 定义头节点
     */
    public Node<T> head = new Node<>(null);
    /**
     * 链表有效元素个数
     */
    private int length=0;
    /**
     * 向单链表中添加一个元素
     * @param data
     */
    public void add(T data){
        //定义当前数据
        Node<T> nodeData = new Node<>(data);
        //定义辅助指针
        Node<T> cur = head;
        //while 循环不断遍历找到最后一个节点
        while (cur.next != null) {
            //只要有下一个节点,辅助指针就向下移动一位
            cur = cur.next;
        }
        //while循环之后,cur已经是最后一个节点,将data赋值到cur的下一个节点上
        cur.next = nodeData;
        //整体链表长度++
        length++;
    }
    /**
     * 向单链表中添加一个元素
     * @param data
     */
    public void add(int index,T data){
        //判断index是否合法
        if(index <0 || index >length){
            System.out.println("index不合法");
            return;
        }
        //定义当前数据
        Node<T> nodeData = new Node<>(data);
        //定义辅助指针
        Node<T> cur = head;
        //找到当前index的元素
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        //将当前节点的next设置成cur的next
        nodeData.next = cur.next;
        //将cur.next设置成nodeData(当前节点)
        cur.next = nodeData;
        //整体链表长度++
        length++;
    }
    /**
     * 遍历输出链表中全部节点
     */
    public void show(){
        //定义辅助指针
        Node<T> cur = head;
        //判断链表中是否存在元素
        if (cur.next == null){
            System.out.println("当前单向链表中元素为空");
            return;
        }
        while (cur.next != null){
            System.out.print(cur.next.data+" ");
            cur = cur.next;
        }
        System.out.print("\n");
    }
    /**
     * 修改指定下标的数据
     * @param index
     * @param data
     */
    public void update(int index,T data){
        Node<T> cur = head;
        if(index > length){
            System.out.println("当前index查过边界");
            return;
        }
        //遍历寻找指定index的节点
        for (int i = 0; i <= index; i++) {
            cur = cur.next;
        }
        //找到之后将新的data赋值上去
        cur.data = data;
    }
    /**
     * 删除指定下标元素
     * @param data
     */
    public void delete(int index){
        Node<T> cur = head;
        if(index > length){
            System.out.println("当前index超过边界");
            return;
        }
        //遍历寻找指定index的节点
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        //找到之后将新的data赋值上去,将后一个data赋值到当前节点上
        cur.data = cur.next.data;
        //将当前节点的next变成当前节点的next.next相当于将当前元素的next节点删掉
        cur.next = cur.next.next;
        //单链表整体有效元素减一
        length--;
    }
    /**
     * 获取指定下标元素的数据
     * @param index
     * @return
     */
    public T get(int index){
        //校验参数是否合法
        if(index<0 || index>length){
            System.out.println("当前index超过边界");
        }
        //定义辅助节点
        Node<T> cur = head;
        //找到对应下标的node
        for (int i = 0; i <=index; i++) {
            cur = cur.next;
        }
        //返回node.data
        return cur.data;
    }
    /**
     * 获取单链表的长度
     * @return
     */
    public int length(){
        return this.length;
    }
    /**
     * 内部节点类
     * @param <T>
     */
    class Node<T>{
        /**
         * 定义数据
         */
        public T data;
        /**
         * 定义下一个节点的
         */
        public Node<T> next;
        public Node(T data) {
            this.data = data;
        }
    }
}

(2)测试代码

public class Main {
    public static void main(String[] args) {
        SingleLinkedList<Integer> singleLink = new SingleLinkedList<>();
        //增加元素
        singleLink.add(1);
        singleLink.add(2);
        singleLink.add(3);
        System.out.print("新增之后:");
        singleLink.show();
        //删除元素
        singleLink.delete(0);
        System.out.print("删除index为0之后:");
        singleLink.show();
        //修改元素
        singleLink.update(0,9);
        System.out.print("修改index为0之后:");
        singleLink.show();
        //获取单链表的长度
        int length = singleLink.length();
        System.out.println("单链表的长度:"+length);
        //获取指定下标的数据
        System.out.println("获取指定下标的数据:"+singleLink.get(1));
        //指定下标插入数据
        singleLink.add(1,6);
        System.out.print("在index为1位置插入数据之后:");
        singleLink.show();
    }
}

d8c31b9ea79042deb34fb08d602126a3.jpg

4.链表的优缺点

  • 优点:
  • 链表的内存空间不连续。
  • 如果知道要处理节点的前一个位置,则进行插入和删除的复杂度为O(1);
  • 如果不知道要处理节点的前一个位置,则进行插入和删除的复杂度为O(N)。
  • 头插、头删的效率高,时间复杂度是O(1)。
  • 没有空间限制,不会溢出,可以存储很多元素。
  • 缺点:
  • 链表不支持随机访问,查找元素效率低,需要遍历节点,时间复杂度是O(n)。


相关文章
|
24天前
|
存储 C语言
【数据结构】手把手教你单链表(c语言)(附源码)
本文介绍了单链表的基本概念、结构定义及其实现方法。单链表是一种内存地址不连续但逻辑顺序连续的数据结构,每个节点包含数据域和指针域。文章详细讲解了单链表的常见操作,如头插、尾插、头删、尾删、查找、指定位置插入和删除等,并提供了完整的C语言代码示例。通过学习单链表,可以更好地理解数据结构的底层逻辑,提高编程能力。
50 4
|
26天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
26天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
1月前
|
算法 Java
数据结构与算法学习五:双链表的增、删、改、查
双链表的增、删、改、查操作及其Java实现,并通过实例演示了双向链表的优势和应用。
17 0
数据结构与算法学习五:双链表的增、删、改、查
|
24天前
|
C语言
【数据结构】双向带头循环链表(c语言)(附源码)
本文介绍了双向带头循环链表的概念和实现。双向带头循环链表具有三个关键点:双向、带头和循环。与单链表相比,它的头插、尾插、头删、尾删等操作的时间复杂度均为O(1),提高了运行效率。文章详细讲解了链表的结构定义、方法声明和实现,包括创建新节点、初始化、打印、判断是否为空、插入和删除节点等操作。最后提供了完整的代码示例。
40 0
|
1月前
|
存储
[数据结构] -- 双向循环链表
[数据结构] -- 双向循环链表
24 0
|
1月前
|
Java C++
【数据结构】探索红黑树的奥秘:自平衡原理图解及与二叉查找树的比较
本文深入解析红黑树的自平衡原理,介绍其五大原则,并通过图解和代码示例展示其内部机制。同时,对比红黑树与二叉查找树的性能差异,帮助读者更好地理解这两种数据结构的特点和应用场景。
32 0
|
1月前
|
存储
探索数据结构:便捷的双向链表
探索数据结构:便捷的双向链表
|
1月前
|
存储
探索数据结构:单链表的实践和应用
探索数据结构:单链表的实践和应用
|
1月前
|
算法 Java
数据结构与算法学习六:单向环形链表应用实例的约瑟夫环问题
这篇文章通过单向环形链表的应用实例,详细讲解了约瑟夫环问题的解决方案,并提供了Java代码实现。
21 0