【2】单链表

【2】单链表

  • 1、单链表
  • 2、单链表的设计
  • 3、接口设计
  • 4、SingleLinkedList
  • 5、node(int index) 返回索引位置的节点
  • 6、clear()
  • 7、添加
  • 8、删除
  • 9、indexOf(E element)

1、单链表

📕动态数组有个明显的缺点
🖊 可能会造成内存空间的大量浪费
📕 能否用到多少就申请多少内存?
🖊 链表可以办到这一点

📕 链表是一种链式存储的线性表,所有元素的内存地址不一定连续
在这里插入图片描述

🖊 每个节点中有一个成员变量指记录着下一个节点的内存地址

2、单链表的设计

在这里插入图片描述

🍀 size 存储单链表的节点个数
🍀 first 被称作头指针:指向头节点
🍀 每个节点(Node)中有 element 属性存储具体的数据;next 属性存储下一个节点的内存地址
🍀 尾节点的 next 属性为 null
🍀 单链表也是线性表(有索引的概念)

3、接口设计

📕 链表的大部分接口和动态数组是一致的
在这里插入图片描述

在这里插入图片描述

public interface List<E> {
    /**
     * 返回存储的元素数量
     */
    int size();

    /**
     * 是否为空
     */
    boolean isEmpty();

    /**
     * 是否包含给定元素
     */
    boolean contains(E element);

    /**
     * 返回索引位置的元素
     */
    E get(int index);

    /**
     * 返回指定元素的索引
     */
    int indexOf(E element);

    /**
     * 添加元素到尾部
     */
    void add(E element);

    /**
     * 往索引位置添加元素
     */
    void add(int index, E element);

    /**
     * 删除索引位置的元素
     *
     * @return 被删除的元素
     */
    E remove(int index);

    /**
     * 清空所有元素
     */
    void clear();

    /**
     * 设置索引位置的元素
     */
    E set(int index, E element);
}

4、SingleLinkedList

在这里插入图片描述

📕往单链表中添加一个数据就会创建的一个 Node 对象

public class SingleLinkedList<E> implements List<E> {
    private int size;
    private Node<E> first;

    /**
     * 返回存储的元素数量
     */
    @Override
    public int size() {
        return 0;
    }

    /**
     * 是否为空
     */
    @Override
    public boolean isEmpty() {
        return false;
    }

    /**
     * 是否包含给定元素
     */
    @Override
    public boolean contains(E element) {
        return false;
    }

    /**
     * 返回索引位置的元素
     */
    @Override
    public E get(int index) {
        return null;
    }

    /**
     * 返回指定元素的索引
     */
    @Override
    public int indexOf(E element) {
        return 0;
    }

    /**
     * 添加元素到尾部
     */
    @Override
    public void add(E element) {

    }

    /**
     * 往索引位置添加元素
     */
    @Override
    public void add(int index, E element) {

    }

    /**
     * 删除索引位置的元素
     *
     * @return 被删除的元素
     */
    @Override
    public E remove(int index) {
        return null;
    }

    /**
     * 清空所有元素
     */
    @Override
    public void clear() {

    }

    /**
     * 设置索引位置的元素
     */
    @Override
    public E set(int index, E element) {
        return null;
    }

    private static final class Node<E> {
        private E element;
        private Node<E> next;

        public Node(E element, Node<E> next) {
            this.element = element;
            this.next = next;
        }
    }

}

5、node(int index) 返回索引位置的节点

在这里插入图片描述

🖊 若需要 index 位置的节点,则从 first 头指针指向的头节点开始 next index 次即可

	/**
	 * 返回index索引处的节点
	 */
	private Node<E> node(int index) {
	    checkIndex(index);
	
	    Node<E> node = first;
	    for (int i = 0; i < index; i++) {
	        node = node.next;
	    }
	    return node;
	}

📕 get(int index) 方法

    /**
     * 返回索引位置的元素
     */
    @Override
    public E get(int index) {
        return node(index).element;
    }

📕 set(int index, E element) 方法

    /**
     * 设置索引位置的元素
     */
    @Override
    public E set(int index, E element) {
        Node<E> node = node(index);
        E e = node.element;
        node.element = element;
        return e;
    }

6、clear()

在这里插入图片描述

🖊 first 头指针指向 null,则头节点会被Java的垃圾回收器回收
🖊 头节点的内存被回收会导致它 next 指向的节点也被回收,最终整个链表就被清空了

    /**
     * 清空所有元素
     */
    @Override
    public void clear() {
        first = null;
        size = 0;
    }

7、添加

在这里插入图片描述

🖊 如果 index == 0(把元素添加到头节点位置):直接让 first 头指针指向新节点,新节点的 next 指向之前的头节点
🖊 如果 index != 0:① 找到 index - 1 索引处的节点 prev;② 新节点的 next 指向 prev.next;③ prev.next 指向新节点

   * 往索引位置添加元素
     */
    @Override
    public void add(int index, E element) {
        checkIndex4Add(index);

        if (index == 0) {
            first = new Node<>(element, first);
        } else {
            Node<E> prev = node(index - 1);
            prev.next = new Node<>(element, prev.next);
        }
        size++;
    }

📕 在编写链表代码时,要注意边界测试,比如 index 为 0size – 1size

边界介绍
0往头节点位置添加元素
size-1边界检查通过
size往链表尾部添加元素
    /**
     * 添加元素到尾部
     */
    @Override
    public void add(E element) {
        add(size, element);
    }

8、删除

在这里插入图片描述

🖊 如果 index == 0(删除头节点元素):直接用头指针 first 指向 first.next
🖊 如果 index != 0:① 找到前一个节点 prev;② prev.next 指向 prev.next.next

    /**
     * 删除索引位置的元素
     *
     * @return 被删除的元素
     */
    @Override
    public E remove(int index) {
        checkIndex(index);

        Node<E> node = first;
        if (index == 0) {
            first = first.next;
        } else {
            Node<E> prev = node(index - 1);
            node = prev.next;
            prev.next = node.next;
        }

        size--;
        return node.element;
    }

📕 在编写链表代码时,要注意边界测试,比如 index 为 0size – 1size

边界介绍
0删除头节点
size-1边界检查通过
size抛异常

9、indexOf(E element)

📕 从 first 开始挨个遍历比较
🖊 考虑 element == null 的情况

    /**
     * 返回指定元素的索引
     */
    @Override
    public int indexOf(E element) {
        Node<E> node = first;
        if (element == null) {
            for (int i = 0; i < size; i++) {
                if (node.element == null) return i;
                node = node.next;
            }
        } else {
            for (int i = 0; i < size; i++) {
                if (element.equals(node.element)) return i;
                node = node.next;
            }
        }

        return ELEMENT_NOT_FOUND;
    }

🍀😀 单链表完整代码

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

云原生架构(微服务、容器云、DevOps、不可变基础设施、声明式API、Serverless、Service Mesh)

前言 读完本文&#xff0c;你将对云原生下的核心概念微服务、容器云、DevOps、Immutable Infrastructure、Declarative-API、Serverless、Service Mesh 等有一个相对详细的了解&#xff0c;帮助你快速掌握云原生的核心和要点。 因题主资源有限, 这里会选用部分云服务商的组件进…

算法沉淀——拓扑排序

前言&#xff1a; 首先我们需要知道什么是拓扑排序&#xff1f; 在正式讲解拓扑排序这个算法之前&#xff0c;我们需要了解一些前置知识&#xff08;和离散数学相关&#xff09; 1、有向无环图&#xff1a; 指的是一个无回路的有向图。 入度&#xff1a;有向图中某点作为图…

数字图像处理——直方图的均衡化

1.方法简介&#xff1a; 直方图均衡化通常用来增加许多图像的全局对比度&#xff0c;尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法&#xff0c;亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度&#xff0c;直方图均衡化通…

01---java面试八股文——mybatis-------10题

1、什么是MyBatis Mybatis是一个半ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了JDBC&#xff0c;开发时只需要关注SQL语句本身&#xff0c;不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql&#xff0c…

基于51单片机和MAX1898的智能手机充电器设计

**单片机设计介绍&#xff0c;基于51单片机和MAX1898的智能手机充电器设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于51单片机和MAX1898的智能手机充电器设计概要 一、引言 随着智能手机的普及&#xff0c;其电池续航…

图像分类实战:深度学习在CIFAR-10数据集上的应用

1.前言 图像分类是计算机视觉领域的一个核心任务&#xff0c;算法能够自动识别图像中的物体或场景&#xff0c;并将其归类到预定义的类别中。近年来&#xff0c;深度学习技术的发展极大地推动了图像分类领域的进步。CIFAR-10数据集作为计算机视觉领域的一个经典小型数据集&…

NumPy介绍及其应用领域

1.NumPy介绍 ​NumPy&#xff08;Numerical Python&#xff09;是 Python 的一个开源的扩展程序库&#xff0c;支持大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。NumPy的前身为Numeric&#xff0c;起初由Jim Hugunin与其他协作者共同开发&…

机器学习和深度学习的简单对比

如图1-2所示&#xff0c;深度学习&#xff08;DeepLearning&#xff0c;DL&#xff09;属于机器学习的子类。它的灵感来源于人类大脑的工作方式&#xff0c;这是利用深度神经网络来解决特征表达的一种学习过程。深度神经网络本身并非是一个全新的概念&#xff0c;可理解为包含多…

Python基础入门 --- 9.异常、模块

文章目录 第九章&#xff1a;9.异常9.1 异常的捕获9.1.1 捕获指定异常9.1.2 捕获多个异常9.1.3 捕获全部异常9.1.4 异常else9.1.5 异常的finally 9.2 异常的传递性9.3 Python模块9.3.1 模块的导入import模块名from 模块名 import 功能名from 模块名 import *as定义别名 9.3.2 自…

2024年水电站大坝安全监测工作提升要点

根据《水电站大坝运行安全监督管理规定》&#xff08;国家发改委令第23号&#xff09;和《水电站大坝运行安全信息报送办法》&#xff08;国能安全〔2016〕261号&#xff09;的相关规定、要求&#xff0c;电力企业应当在汛期向我中心报送每日大坝汛情。近期&#xff0c;全国各地…

帆软报表踩坑日记

最近公司项目要是使用报表&#xff0c;公司使用的是帆软这个国产软件&#xff0c;自己也是学习使用&#xff0c;在使用的过程中记一下问题以及解决方式 公司使用的是帆软8这个版本&#xff0c;比较老了。 首先是表格中的扩展&#xff0c;就是当我们根据数据库查询数据然后放到表…

谷粒商城实战(007 压力测试)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第141p-第p150的内容 简介 安装jmeter 安装jmeter 使用中文 这样写就是200个线程循环100次 一共是2万个请求 介绍线程组 添加请求 可以是htt…

供应链销售数据分析丨跟张良均老师学大数据人工智能(第二期)

师傅带练 项目背景 通过大数据分析怡亚通供应链商品的销售数据&#xff0c;分析不同店铺地址、不同销售季节和不同产品的销售数据&#xff0c;可以给于客户铺货支持以及经营策略建议&#xff0c;帮助怡亚通更好地优化库存管理、供货策略和市场营销活动&#xff0c;从而提升销…

计算机视觉的应用25-关于Deeplab系列语义分割模型的应用场景,以及空洞卷积的介绍

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用25-关于Deeplab系列语义分割模型的应用场景&#xff0c;以及空洞卷积的介绍。Deeplab是Google研发的一系列深度学习模型&#xff0c;主要用于图像语义分割任务&#xff0c;其在众多应用场景中展现出…

56、FreeRTOS/GPIO与定时器相关学习20240329

一、代码实现控制开发板上的指示灯闪烁。 /* USER CODE BEGIN 0 */ //利用定时器机制 定时器溢出时对应的回调函数实现如下 //本次实现控制PB0&#xff0c;PB1两个灯 int flag1 0,flag2 0;//使用一个标记执行以下代码 会造成一个灯常亮 另一个常灭 void HAL_TIM_PeriodElaps…

JavaSE day15 笔记

第十五天课堂笔记 数组 可变长参数★★★ 方法 : 返回值类型 方法名(参数类型 参数名 , 参数类型 … 可变长参数名){}方法体 : 变长参数 相当于一个数组一个数组最多只能有一个可变长参数, 并放到列表的最后parameter : 方法参数 数组相关算法★★ 冒泡排序 由小到大: 从前…

【threejs】较大物体或shape的贴图较小问题处理方法

问题 有的场景内相对体型差距过大的物体&#xff08;如山地 海洋等&#xff09;由于尺寸问题&#xff0c;加载贴图过于小&#xff0c;同时shader也无法完全展示&#xff0c;如图 我们可以获取物体的uv&#xff0c;进行缩放使得贴图可以完全展开 如果uv是乱的 可以用xyz坐标最…

模组软件通用|GNSS坐标系的转换

“GNSS定位不准确&#xff0c;漂移了好几公里&#xff0c;是怎么回事呢&#xff1f;”很多用户在初次使用GNSS定位时都会有这样的问题&#xff0c;这主要是由于GNSS坐标系转换错误造成的位置偏移问题。下面将从常见坐标系、国内地图软件采用的坐标系、经纬度表示方法、示例以及…

Qt 完成图片的缩放拖动

1. 事件和函数 主要使用事件paintEvent(QPaintEvent *event)和drawTiledPixmap函数实现绘图。 paintEvent事件在改变窗口大小、移动窗口、手动调用update等情形下会被调用。需先了解下绘图该函数的用法。 - QPainter::drawTiledPixmap(int x, int y, int w, int h, const QPi…

深入并广泛了解Redis常见的缓存使用问题

Redis 作为一门主流技术&#xff0c;缓存应用场景非常多&#xff0c;很多大中小厂的项目中都会使用redis作为缓存层使用。 但是Redis作为缓存&#xff0c;也会面临各种使用问题&#xff0c;比如数据一致性&#xff0c;缓存穿透&#xff0c;缓存击穿&#xff0c;缓存雪崩&#…