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

文章介绍了单链表的概念,它是一种链式存储结构,数据节点由元素和指针组成,非顺序存储。接着详细阐述了单链表的实现,包括向链表末尾和指定位置添加元素、删除元素、获取和修改指定位置元素以及遍历链表的方法。此外,还提供了单链表的Java代码实现示例。文章最后讨论了链表的优点,如插入和删除操作高效,以及缺点,如不支持随机访问,查找效率较低。
摘要由CSDN通过智能技术生成
1.什么是单链表

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

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

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

在这里插入图片描述

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)定义数据节点实体

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

(7)循环遍历输出

在这里插入图片描述

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

在这里插入图片描述

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();
    }
}

在这里插入图片描述

4.链表的优缺点
  • 优点:

    • 链表的内存空间不连续。

    • 如果知道要处理节点的前一个位置,则进行插入和删除的复杂度为O(1);

    • 如果不知道要处理节点的前一个位置,则进行插入和删除的复杂度为O(N)。

    • 头插、头删的效率高,时间复杂度是O(1)。

    • 没有空间限制,不会溢出,可以存储很多元素。

  • 缺点:

    • 链表不支持随机访问,查找元素效率低,需要遍历节点,时间复杂度是O(n)。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网小阿祥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值