Java实现数据结构——双链表

news2024/11/15 12:18:34

目录

一、前言

二、实现

2.1 类的创建

三、对链表操作实现

3.1 打印链表

3.2 插入数据

3.2.1 申请新节点

3.2.2 头插

​编辑

3.2.3 尾插

3.2.4 链表长度

3.2.5 任意位置插入

3.3 删除数据

3.3.1 头删

3.3.2 尾删

3.3.3 删除指定位置数据

3.3.4 删除指定数据

3.3.5 删除所有指定数据 

3.3.6 删除链表 

四、LinkedList

4.1 什么是 LinkedList

4.2 LinkedList 的使用

​编辑

4.2.1 LinkedList的构造方法

4.2.2 常用方法

​编辑

​编辑

五、ArrayList和LinkedList的区别


一、前言

更详细的理论请移步笔者的另一文章

http://t.csdnimg.cn/4Mtne

二、实现

2.1 类的创建

双向链表就是在单链表的基础上加上了一个 prev,存放上一个节点的地址

public class MyLinkedList {
    //    自己实现双向链表
    static class ListNode {
        int val;
        ListNode prev;//前
        ListNode next;//后

        public ListNode(int val) {
            this.val = val;
        }
    }

    ListNode head = null;//头
    ListNode last = null;//尾
}

需要什么方法在后续再补充

三、对链表操作实现

3.1 打印链表

可正序打印

也可逆序打印

 public void printHead() {
        //正序打印
        ListNode cur = this.head;
        if (cur == null) {
            System.out.println("当前链表为空!");
            return;
        }
        while (cur != null) {
            System.out.println(cur.val);
            cur = cur.next;
        }
    }

public void printLast(){
        //逆序打印
        ListNode cur = this.last;
        if(cur == null){
            System.out.println("当前链表为空!");
            return;
        }
        while (cur != null) {
            System.out.println(cur.val);
            cur = cur.prev;
        }
    }

3.2 插入数据

3.2.1 申请新节点

   public ListNode buyNode(int data) {
//    申请新节点
        ListNode newnode = new ListNode(data);
        return newnode;
    }

3.2.2 头插

链表为空就让链表的 headlast 都等于这个新节点

若链表不为空

原头节点的 prev 保存新插入节点的地址

新插入节点的 next 保存原头节点的地址

新插入节点成为新的头节点

 public void addFirst(int data) {
        //头插
        if (this.head == null) {
            this.head = buyNode(data);
            this.last = this.head;
            return;
        }
        ListNode newnode = buyNode(data);
        newnode.next = this.head;//新插入节点的 next 保存原头节点的地址
        this.head.prev = newnode;//原头节点的 prev 保存新插入节点的地址
        this.head = newnode;//新插入节点成为新的头节点
    }

测试

 public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addFirst(1);
        linkedList.addFirst(2);
        linkedList.addFirst(3);
        linkedList.addFirst(4);

        linkedList.printHead();
        System.out.println("==============");
        linkedList.printLast();
    }


3.2.3 尾插

链表为空就让链表的 headlast 都等于这个新节点

若链表不为空

last.next 保存新插入节点的地址

新插入节点的 prev 保存 last 的地址

新插入节点成为 last 

public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addLast(5);
        linkedList.addLast(6);
        linkedList.addLast(7);
        linkedList.addLast(8);

        linkedList.printHead();
        System.out.println("==============");
        linkedList.printLast();
    }

测试

public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addLast(5);
        linkedList.addLast(6);
        linkedList.addLast(7);
        linkedList.addLast(8);

        linkedList.printHead();
        System.out.println("==============");
        linkedList.printLast();
    }


3.2.4 链表长度

 public int size() {
        //返回链表节点个数
        ListNode cur = this.head;
        int count = 0;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

3.2.5 任意位置插入

插入时需要检查坐标的合法性

合法区间是[0,size()]

指定位置合法后

新节点的 prev 存储原位置节点 prev 的地址

新节点的 next 存储原位置节点的地址

原位置的 prev 存储为新节点的地址

原位置前一节点的 next 存储为新节点的地址

为方便观察修改一下打印方法

  public void printHead() {
        //正序打印
        ListNode cur = this.head;
        if (cur == null) {
            System.out.println("当前链表为空!");
            return;
        }
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
    }

    public void printLast() {
        //逆序打印
        ListNode cur = this.last;
        if (cur == null) {
            System.out.println("当前链表为空!");
            return;
        }
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.prev;
        }
    }

测试

 public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addLast(5);
        linkedList.addLast(6);
        linkedList.addLast(7);
        linkedList.addLast(8);
        linkedList.printHead();
        System.out.println();
        System.out.println("==========");
        linkedList.addAny(1, 99);
        linkedList.addAny(2, 199);
        linkedList.addAny(3, 299);
        linkedList.addAny(0, 122);
        linkedList.addAny(linkedList.size(), 999);
        linkedList.printHead();

    }

 


3.3 删除数据

3.3.1 头删

由于此处是基础数据类型

不需要对节点中存储的数据进行置空

如果存储的是引用数据类型就需要置空

将原头节点置空

头节点的下一个节点成为新的头节点

新的头节点的 prev 需要置空

  public void removeFirst() {
        //头删
        if (this.head == null) {
            System.out.println("当前链表为空!");
            return;
        }
        ListNode tmp = this.head.next;
//        this.head.val = null;//由于此处是基础数据类型 不需要对节点中存储的数据进行置空 如果存储的是引用数据类型就需要置空
        this.head = null;
        this.head = tmp;
        if(this.head == null){
            this.last = null;
        }else {
            this.head.prev = null;//新的头节点的 prev 需要置空

        }
    }

测试

  public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addFirst(1);
        linkedList.addFirst(2);
        linkedList.addFirst(3);
        linkedList.addFirst(4);

        linkedList.printHead();

        linkedList.removeFirst();
        System.out.println();
        linkedList.printHead();

        linkedList.removeFirst();
        System.out.println();
        linkedList.printHead();

        linkedList.removeFirst();
        System.out.println();
        linkedList.printHead();

        linkedList.removeFirst();
        System.out.println();
        linkedList.printHead();
    }


3.3.2 尾删

由于此处是基础数据类型

不需要对节点中存储的数据进行置空

如果存储的是引用数据类型就需要置空

尾节点的前一个节点成为新的尾节点

新的尾节点的 next 需要置空

   public void removeLast() {
        //尾删
        if (this.last == null) {
            System.out.println("当前链表为空!");
            return;
        }
//        this.last.val = null;由于此处是基础数据类型 不需要对节点中存储的数据进行置空 如果存储的是引用数据类型就需要置空
        ListNode tmp = this.last.prev;
        this.last = null;
        this.last = tmp;
        if(this.last == null){
            this.head = null;
        }
        else {
            this.last.next = null;//新的尾节点的 next 需要置空

        }
    }

测试

    public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addFirst(1);
        linkedList.addFirst(2);
        linkedList.addFirst(3);
        linkedList.addFirst(4);

        linkedList.printHead();

        linkedList.removeLast();
        System.out.println();
        linkedList.printHead();

        linkedList.removeLast();
        System.out.println();
        linkedList.printHead();

        linkedList.removeLast();
        System.out.println();
        linkedList.printHead();

        linkedList.removeLast();
        System.out.println();
        linkedList.printHead();
    }


3.3.3 删除指定位置数据

删除时需要检查坐标的合法性

合法区间是[0,size())

将删除位置前节点的 next 保存为删除节点位置后节点的地址

将删除位置后节点的 prev 保存为删除节点位置前节点的地址

  public void removeAny(int index) {
        if (this.head == null) {
            System.out.println("当前链表为空!");
            return;
        }
        if (index < 0 && index >= this.size()) {
            throw new IndexillegalityException("下标不合法!");
        }
        if (index == 0) {
            removeFirst();
            return;
        } else if (index == size() - 1) {
            removeLast();
            return;
        }
        ListNode cur = this.head;
        while (index != 0) {
            //找要删除的节点
            cur = cur.next;
            index--;
        }
        cur.prev.next = cur.next;
        cur.next.prev = cur.prev;
        cur = null;

    }

测试

 public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addFirst(1);
        linkedList.addFirst(2);
        linkedList.addFirst(3);
        linkedList.addFirst(4);
        linkedList.printHead();
        System.out.println();

        linkedList.removeAny(1);
        linkedList.printHead();
        System.out.println();

        linkedList.removeAny(1);
        linkedList.printHead();
        System.out.println();

        linkedList.removeAny(1);
        linkedList.printHead();
        System.out.println();

        linkedList.removeAny(1);
        linkedList.printHead();
        System.out.println();
    }

抛了一个空指针异常

说明在链表只剩下一个节点的时候需要特殊处理

    public void removeAny(int index) {
        if (this.head == null) {
            System.out.println("当前链表为空!");
            return;
        }
        if (index < 0 && index >= this.size()) {
            throw new IndexillegalityException("下标不合法!");
        }
        if (index == 0) {
            removeFirst();
            return;
        } else if (index == size() - 1) {
            removeLast();
            return;
        }
        ListNode cur = this.head;
        while (index != 0) {
            //找要删除的节点
            cur = cur.next;
            index--;
        }
        if(cur == null ){
            //判断是否只有一个节点
            //cur在移动后如果等于空,就说明一定只剩下一个节点
            this.last = null;
            this.head = null;
        }else {
            cur.prev.next = cur.next;
            cur.next.prev = cur.prev;
            cur = null;
        }
    }


3.3.4 删除指定数据

将删除位置前节点的 next 保存为删除节点位置后节点的地址

将删除位置后节点的 prev 保存为删除节点位置前节点的地址

对头和尾做单独处理

 public void removeData(int data){
        //删除指定数据
        if (this.head == null) {
            System.out.println("当前链表为空!");
            return;
        }
        ListNode cur = this.head;
        while (cur != null){
            if(cur.val == data){
                if(cur == head){
                    removeFirst();
                    return;
                }else if(cur == last){
                    removeLast();
                    return;
                }else {
                    cur.prev.next = cur.next;
                    cur.next.prev = cur.prev;
                }
            }
            cur = cur.next;
        }
        System.out.println("当前链表中没有您要删除的数据");
    }

测试

 public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addFirst(1);
        linkedList.addFirst(2);
        linkedList.addFirst(3);
        linkedList.addFirst(4);
        linkedList.printHead();
        System.out.println();

        linkedList.removeData(4);
        linkedList.printHead();
        System.out.println();

        linkedList.removeData(3);
        linkedList.printHead();
        System.out.println();
        
        linkedList.removeData(2);
        linkedList.printHead();
        System.out.println();

        linkedList.removeData(1);
        linkedList.printHead();
    }


3.3.5 删除所有指定数据 

将链表中所有节点值等于 data 的节点全部删除

将3.3.4 的方法中进行删除后继续遍历链表

遇到节点值为 data 的继续删除即可

  public void removeDataAll(int data){
        //删除所有节点值为data的节点
        if (this.head == null) {
            System.out.println("当前链表为空!");
            return;
        }
        boolean flg = false;

        ListNode cur = this.head;
        while (cur != null){
            if(cur.val == data){
                flg = true;
                if(cur == head){
                    removeFirst();
                }else if(cur == last){
                    removeLast();
                }else {
                    cur.prev.next = cur.next;
                    cur.next.prev = cur.prev;
                }
            }
            cur = cur.next;
        }
        if(!flg){
            System.out.println("当前链表中没有您要删除的数据!");

        }else {
            System.out.println("删除成功!");
        }
    }

测试

public static void main(String[] args) {
        MyLinkedList linkedList = new MyLinkedList();
        linkedList.addFirst(4);
        linkedList.addFirst(4);
        linkedList.addFirst(4);
        linkedList.addFirst(4);
        linkedList.addFirst(2);
        linkedList.addFirst(1);
        linkedList.addFirst(5);
        linkedList.addFirst(6);
        linkedList.addFirst(4);

        linkedList.printHead();
        System.out.println();

        linkedList.removeDataAll(4);
        linkedList.printHead();
        System.out.println();

    }


3.3.6 删除链表 

即将所有节点全部删除

让每个节点的 next ,prev 都置空

  public void clear(){
        //删除整个链表
        if (this.head == null) {
            System.out.println("当前链表为空!");
            return;
        }
        ListNode cur = this.head;
        while (cur!= null){
//            cur.val = null;如果是引用数据类型就需要置空
            ListNode tmp = cur.next;
            cur.next = null;
            cur.prev = null;
            cur = tmp;
        }
        this.head = null;
        this.last = null;
    }

四、LinkedList

Java 中已经封装好了 LinkedList

4.1 什么是 LinkedList

LinkedList 官方文档 https://docs.oracle.com/javase/8/docs/api/java/util/LinkedList.html

LinkedList  的底层是双向链表结构 ( 链表后面介绍 ) ,由于链表没有将元素存储在连续的空间中,元
素存储在单独的节点中,然后通过引用将节点连接起来了,因此在在任意位置插入或者删除元素
时,不需要搬移元素,效率比较高。
1. LinkedList  实现了  List 接口
2. LinkedList  的底层使用了双向链表
3. LinkedList  没有实现  RandomAccess  接口,因此  LinkedList  不支持随机访问
4. LinkedList  的任意位置插入和删除元素时效率比较高,时间复杂度为 O(1)
5. LinkedList  比较适合任意位置插入的场景

4.2 LinkedList 的使用

4.2.1 LinkedList的构造方法

    public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
        LinkedList<Number> linkedList2 = new LinkedList<>();

    }


4.2.2 常用方法

方法功能
boolean add (E e)
尾插 e
void add (int index, E element)
将 e 插入到 index 位置
e 插入到 index 位置
boolean addAll (Collection<? extends E> c)
尾插 c 中的元素
E remove (int index)
删除 index 位置元素
E get (int index)
获取下标 index 位置元素
E set (int index, E element)
将下标 index 位置元素设置为 element
void clear ()
清空
boolean contains (Object o)
判断 o 是否在线性表中
int indexOf (Object o)
返回第一个 o 所在下标
int lastIndexOf (Object o)
返回最后一个 o 的下标
List<E> subList (int fromIndex, int toIndex)
截取部分 list
…………

这里只说说 addAll subList

 public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
        linkedList.add(new Integer(2));
        linkedList.add(new Integer(3));
        linkedList.add(new Integer(4));
        linkedList.add(new Integer(5));
        System.out.println(linkedList);

        List<Integer> list2 = linkedList.subList(1,3);
        System.out.println(list2);

        linkedList.set(1,10);
        System.out.println(list2);
    }

与 ArrayList 实现的 subList

subList 只是将对应区间的地址截取出来返回

而不是产生新的对象返回


与 ArrayList 实现的 addAll 类似

形参 c 的类型必须是实现了 Collection 接口 

且其中存放的数据必须是 E 本身或 E 的子类

 public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<>();
        linkedList.add(new Integer(2));
        linkedList.add(new Integer(3));
        linkedList.add(new Integer(4));
        linkedList.add(new Integer(5));

        LinkedList<Number> linkedList2 = new LinkedList<>(linkedList);
        System.out.println(linkedList);
        System.out.println(linkedList2);
        
    }

五、ArrayListLinkedList的区别

不同点
ArrayList
LinkedList
存储空间上
物理上一定连续
逻辑上连续,但物理上不一定连续
随机访问
支持 O(1)
不支持: O(N)
头插
需要搬移元素,效率低 O(N)
只需修改引用的指向,时间复杂度为 O(1)
插入
空间不够时需要扩容
没有容量的概念
应用场景
元素高效存储 + 频繁访问
任意位置插入和删除频繁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1925229.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

王道计算机考研数据结构思维导图笔记(持续更新)

第1章 绪论 1.1 数据结构的基本概念 1.1.1 基本概念和术语 1.1.1 数据结构三要素 1.2 算法和算法评价 1.2.1算法的基本概念 1.2.2 算法效率的度量 第2章 线性表 2.1 线性表的定义和基本操作 2.1.1 线性表的定义 2.1.2 线性表的基本操作 2.2.1 顺序表上的定义 2.2.2 顺序…

Power Apps使用oData访问表数据并赋值前端

在使用OData查询语法通过Xrm.WebApi.retrieveMultipleRecords方法过滤数据时&#xff0c;你可以指定一个OData $filter 参数来限制返回的记录集。 以下是一个使用Xrm.WebApi.retrieveMultipleRecords方法成功的例子&#xff0c;它使用了OData $filter 参数来查询实体的记录&am…

期货交易记录20240714

文章目录 期货交易系统构建步骤一、选品二、心态历练三、何时开仓3.1、开仓纪律3.2、开仓时机3.3、开仓小技巧 四、持仓纪律五、接下来的计划 2024年7月15号&#xff0c;期货交易第6篇记录。这一篇文中主要记录下&#xff0c;根据交易保证金筛选品种。 交易记录&#xff1a;目…

internet download manager(IDM下载器) 6.42.8.2下载安装使用指南

internet download manager(IDM下载器) 6.42.8.2Z是一款功能强大的下载加速工具&#xff0c;能够显著提升您的下载速度&#xff0c;最高可达500%。它不仅能够加速下载&#xff0c;还能对下载任务进行智能调度&#xff0c;并具备恢复中断下载的能力。根据用户评价&#xff0c;无…

6.S081的Lab学习——Lab10: mmap

文章目录 前言mmap(hard)提示&#xff1a;解析 总结 前言 一个本硕双非的小菜鸡&#xff0c;备战24年秋招。打算尝试6.S081&#xff0c;将它的Lab逐一实现&#xff0c;并记录期间心酸历程。 代码下载 官方网站&#xff1a;6.S081官方网站 安装方式&#xff1a; 通过 APT 安装…

Re:从零开始的C++世界——(一)入门基础

文章目录 C发展历史1.命名空间1.1 namespace的价值1.2 namespace的定义1.3 命名空间使⽤ 2.C输⼊&输出3.缺省参数3.1 缺省参数的概念3.2 缺省参数的分类 4.函数重载5.引⽤5.1引⽤的概念和定义5.2 引⽤的特性5.3 const引⽤5.4 使用场景5.5 指针和引⽤的关系 6.内联函数6.1内…

RDNet实战:使用RDNet实现图像分类任务(二)

文章目录 训练部分导入项目使用的库设置随机因子设置全局参数图像预处理与增强读取数据设置Loss设置模型设置优化器和学习率调整策略设置混合精度&#xff0c;DP多卡&#xff0c;EMA定义训练和验证函数训练函数验证函数调用训练和验证方法 运行以及结果查看测试完整的代码 在上…

从零开始做题:迷失幻境

题目 给出一个磁盘虚拟文件 解题 下载附件然后解压,得到一个虚拟机文件,使用的是DiskGenius磁盘工具打开 这样他里面的文件就全部展现出来了 我们可以看到有很多图片&#xff0c;和一个txt文档&#xff0c;还有几个没有后缀的文件&#xff0c;图片这么多&#xff0c;所以我…

自动驾驶中的人机互相接管问题讨论

一、背景 人机接管&#xff08;human takeover&#xff09;是指在自动驾驶过程中&#xff0c;当系统遇到超出其处理能力或预设安全阈值的情况时&#xff0c;将控制权交还给驾驶员的过程。这一环节的设计直接关系到自动驾驶技术的实用性与安全性&#xff0c;是目前研究和实践中…

idea启动ssm项目详细教程

前言 今天碰到一个ssm的上古项目&#xff0c;项目没有使用内置的tomcat作为服务器容器&#xff0c;这个时候就需要自己单独设置tomcat容器。这让我想起了我刚入行时被外置tomcat配置支配的恐惧。现在我打算记录一下配置的过程&#xff0c;希望对后面的小伙伴有所帮助吧。 要求…

计算机视觉之Vision Transformer图像分类

Vision Transformer&#xff08;ViT&#xff09;简介 自注意结构模型的发展&#xff0c;特别是Transformer模型的出现&#xff0c;极大推动了自然语言处理模型的发展。Transformers的计算效率和可扩展性使其能够训练具有超过100B参数的规模空前的模型。ViT是自然语言处理和计算…

第零章 HCIA复习

目录 HCIA复习 一、OSI七层模型 二、TCP/UDP协议 传输层协议 TCP/IP协议簇 封装/解封装 模型区别 协议号和类型字段 类型字段 协议号 UDP协议头部&#xff1a; TCP协议头部&#xff1a; IP报文参数&#xff1a; 三、DHCP协议 定义 PC端初次获取IP地址 交换机转…

Linux vim的使用(一键安装则好用的插件_forcpp),gcc的常见编译链接操作

vim 在Linux系统上vim是个功能还比较完善的软件。但是没装插件的vim用着还是挺难受的&#xff0c;所以我们直接上一款插件。 我们只需要在Linux上执行这个命令就能安装(bite提供的) curl -sLf https://gitee.com/HGtz2222/VimForCpp/raw/master/install.sh -o ./install.sh …

基于1bitDAC的MU-MIMO的非线性预编码算法matlab性能仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 基于1-bit DAC的非线性预编码背景 4.2 ZF&#xff08;Zero-Forcing&#xff09; 4.3 WF&#xff08;Water-Filling&#xff09; 4.3 MRT&#xff08;Maximum Ratio Transmission&…

昇思25天学习打卡营第09天|保存与加载

在训练网络模型的过程中&#xff0c;实际上我们希望保存中间和最后的结果&#xff0c;用于微调&#xff08;fine-tune&#xff09;和后续的模型推理与部署&#xff0c;本章节我们将介绍如何保存与加载模型。 import numpy as np import mindspore from mindspore import nn fr…

【云岚到家】-day05-6-项目迁移-门户-CMS

【云岚到家】-day05-6-项目迁移-门户-CMS 4 项目迁移-门户4.1 迁移目标4.2 能力基础4.2.1 缓存方案设计与应用能力4.2.2 静态化技术应用能力 4.3 需求分析4.3.1 界面原型 4.4 系统设计4.4.1 表设计4.4.2 接口与方案4.4.2.1 首页信息查询接口4.4.3.1 数据缓存方案4.4.3.2 页面静…

C++相关概念和易错语法(20)(赋值兼容转换、多继承、继承与组合)

1.赋值兼容转换 赋值兼容转换有一点易混&#xff0c;先看一下下面的代码&#xff0c;想想a、b、c对象里面存的什么&#xff0c;顺便结合以前的知识&#xff0c;对继承加深理解。 #include <iostream> using namespace std;class A { protected:A(int a):_a(a){}int _a; …

PostgreSQL 中如何解决因频繁的小事务导致的性能下降?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 PostgreSQL 中解决因频繁小事务导致性能下降的方法 PostgreSQL 中解决因频繁小事务导致性能下降的方法…

使用机器学习 最近邻算法(Nearest Neighbors)进行点云分析 (scikit-learn Open3D numpy)

使用 NearestNeighbors 进行点云分析 在数据分析和机器学习领域&#xff0c;最近邻算法&#xff08;Nearest Neighbors&#xff09;是一种常用的非参数方法。它广泛应用于分类、回归和聚类分析等任务。下面将介绍如何使用 scikit-learn 库中的 NearestNeighbors 类来进行点云数…

C++ | Leetcode C++题解之第233题数字1的个数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countDigitOne(int n) {// mulk 表示 10^k// 在下面的代码中&#xff0c;可以发现 k 并没有被直接使用到&#xff08;都是使用 10^k&#xff09;// 但为了让代码看起来更加直观&#xff0c;这里保留了 klong l…