数据结构之单链表基本操作

news2024/11/25 20:47:20

🤷‍♀️🤷‍♀️🤷‍♀️ 今天给大家分享的是单链表的基本操作。

清风的个人主页 

🎉欢迎👍点赞✍评论❤️收藏

😛😛😛希望我的文章能对你有所帮助,有不足的地方还请各位看官多多指教,大家一起学习交流!

动动你们发财的小手,点点关注点点赞!在此谢过啦!哈哈哈!😛😛😛

 

目录

 一、接口定义

二、类定义

三、方法实现

3.1创建单链表(初始化创建)

3.2头插法插入节点

3.3尾插法插入节点

3.4指定位置插入节点

3.5判断节点是否包含在链表中

3.6删除值为key的节点

 3.7删除所有值为key的节点

3.8得到链表长度

3.9清空链表

3.10显示链表(打印)


源码链接:>清风的Gitee主页 

 一、接口定义

还是和之前的顺序表一样,定义一个接口。后续通过链表类去实现这个定义的接口。

interface SingleLinkedList {
    //头插法
    void addFirst(int data);
    //尾插法
    void addLast(int data);
    //任意位置插入,第一个数据节点为0号下标
    void addIndex(int index,int data);
    //查找是否包含关键字key是否在单链表当中
    boolean contains(int key);
    //删除第一次出现关键字为key的节点
    void remove(int key);
    //删除所有值为key的节点
     void removeAllKey(int key);
    //得到单链表的长度
     int size();
     void clear();
     void display();
}

二、类定义

定义一个链表类,它是由各个节点构成的,因此还需要在链表类内定义一个关于节点的内部类。代码如下:
 

public class MyLinkedList implements SingleLinkedList {

    class LinkNode {
        public int val;
        public LinkNode next;

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

    public LinkNode head;
}

三、方法实现

3.1创建单链表(初始化创建)

每次通过LinkNode类定义的节点去new一个新的节点并通过构造函数设置初始值,节点定义完成后,通过各个节点的next域把各个节点之间联系起来,便成功创建了一个单链表。

    public void creatLinkedList() {
        LinkNode node1 = new LinkNode(12);
        LinkNode node2 = new LinkNode(23);
        LinkNode node3 = new LinkNode(34);
        LinkNode node4 = new LinkNode(45);
        LinkNode node5 = new LinkNode(56);
        node1.next = node2;
        node2.next = node3;
        node3.next = node4;
        node4.next = node5;

        this.head = node1;

    }

3.2头插法插入节点

    //头插法
    public void addFirst(int data) {
        LinkNode newnode = new LinkNode(data);
        if (this.head == null) {
            this.head = newnode;
        } else {
            newnode.next = this.head;
            this.head = newnode;
        }
    }

3.3尾插法插入节点

尾插法插入节点时,首先要找到单链表的最后一个节点,再去插入。 

  • 注意,找到单链表的最后一个节点,在while循环里面的控制条件是:cur.next!=null,而不是cur!=null,这一点要切记!!!在我们刷题的时候,很多情况下都要去遍历找节点,因此一定要注意。(cur是一个引用,从head开始遍历)
  • 下图是while(cur.next!=null),循环条件结束的时候,cur所指向的位置:>

 

  • 下图是while(cur!=null),循环条件结束的时候,cur所指向的位置:> 

 

    public void addLast(int data) {
        LinkNode newnode = new LinkNode(data);
        if (this.head == null) {
            this.head = newnode;
            return;
        }
        LinkNode cur = this.head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = newnode;

    }

3.4指定位置插入节点

在指定位置插入,首先要判断插入位置是否合法。其次,若是在头节点插入,调用头插法即可,若是在尾节点插入,调用尾插法即可。然后,就需要找到指定的位置,此时应该找的是指定位置的前驱节点,通过指定位置的前驱节点的next域指向要插入的节点即可。当然在执行这一步骤之前,我们还需要先把前驱节点的next域所指向的节点交给要插入的节点的next域。

    public void addIndex(int index, int data) {
        if (index < 0 || index > size()) {
            System.out.println("插入位置不合法:>" + index);
            return;
        }
        if (index == 0) {
            addFirst(data);
            return;
        }
        if (index == size()) {
            addLast(data);
            return;
        }
        LinkNode cur = this.head;
        LinkNode newnode = new LinkNode(data);
        for (int i = 0; i < index - 1; i++) {
            cur = cur.next;
        }
        newnode.next = cur.next;
        cur.next = newnode;
    }

3.5判断节点是否包含在链表中

只需遍历链表,比较节点的值是否和要判断节点的值相等即可。

    public boolean contains(int key) {
        LinkNode cur = this.head;
        while (cur != null) {
            if (cur.val == key) {
                return true;
            }
            cur = cur.next;
        }
        return false;
    }

3.6删除值为key的节点

要先找到值为key的节点的前驱节点:

    private LinkNode findPrev(int key) {
        LinkNode cur = this.head;
        while ((cur.next != null)) {
            if (cur.next.val == key) {
                return cur;
            }
            cur = cur.next;
        }
        return cur;
    }

以下图为例,假设删除34:>

    public void remove(int key) {
        if (this.head == null) {
            System.out.println("链表为空,无法删除!!!");
            return;
        }
        if (this.head.val == key) {
            this.head = this.head.next;
            return;
        }
/*        while(cur.next!=null){
            //找到要删除节点的前驱
            if(cur.next.val==key){
                LinkNode del=cur.next;
                cur.next=del.next;
                return;

            }else {
                cur=cur.next;
            }
        }*/
        LinkNode prev = findPrev(key);
        if (prev == null) {
            System.out.println("无要删除的数字:>" + key);
            return;
        }
        LinkNode del = prev.next;
        prev.next=del.next;
    }

 3.7删除所有值为key的节点

方法是通过双指针来解决:>

假设删除值为23的所有节点。

cur往前走,发现值为23的节点,进行删除操作:>

删除之后,prev指向了23的下一个节点。

 

删除完成后,prev不动,cur继续往后遍历:>

 

当cur这个引用所指向的节点的值不是23是,prev也要继续往前挪:>

 

如此进行下去,即可删除所有值为23的节点。

下面是实现代码:> 

    public void removeAllKey(int key) {
        if (this.head == null) {
            System.out.println("链表为空!");
            return;
        }
        LinkNode prev = head;
        LinkNode cur = head.next;
        while (cur != null) {
            if (cur.val == key) {
                prev.next = cur.next;
                cur = cur.next;
            } else {
                prev = cur;
                cur = cur.next;
            }
        }
        if (head.val == key) {
            head = head.next;
        }
    }

3.8得到链表长度

很简单,只需通过一个引用遍历即可。如果引用所指的对象不是空,那么计数器+1。

    public int size() {
        LinkNode cur = this.head;
        int count = 0;
        while (cur != null) {
            count++;
            cur = cur.next;
        }
        return count;
    }

3.9清空链表

    public void clear() {
        LinkNode cur = this.head;
        while (cur != null) {
            LinkNode curNext = cur.next;
            cur.next = null;
            cur = curNext;
        }
        head.next = null;
    }

3.10显示链表(打印)

    public void display(LinkNode newhead) {
        LinkNode cur = newhead;
        while (cur != null) {
            System.out.print(cur.val + " ");
            cur = cur.next;
        }
        System.out.println();
    }

🎉好啦,今天的分享就到这里!!

✨创作不易,还希望各位大佬支持一下!

👍点赞,你的认可是我创作的动力!

⭐收藏,你的青睐是我努力的方向!

✏️评论:你的意见是我进步的财富!

 

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

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

相关文章

公众号标签

公众号标签 本章节&#xff0c;讲解公众号标签的相关内容&#xff0c;支持对标签进行创建、查询、修改、删除等操作&#xff0c;也可以对用户进行打标签、取消标签等操作&#xff0c;对应 《微信公众号官方文档 —— 用户标签管理》 (opens new window)文档。 #1. 表结构 公众…

ubuntu 火焰图脚本

环境ubuntu1804 x86_64 #!/bin/bash if [ "$2_" "_" ];thenecho "usage ./fire.sh oncpu/offcpu pid"exit fiif [ "$1_" "oncpu_" ];thensudo perf record -F 99 -p $2 -g -- sleep 10syncsudo perf script > out.pe…

openai自定义API操作 API 返回值说明

custom-自定义API操作 openai.custom 公共参数 名称类型必须描述keyString是调用key&#xff08;获取测试key&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,item_search_shop等]cacheStrin…

python爬虫hook定位技巧、反调试技巧、常用辅助工具

一、浏览器调试面板介绍 二、hook定位、反调试 Hook 是一种钩子技术&#xff0c;在系统没有调用函数之前&#xff0c;钩子程序就先得到控制权&#xff0c;这时钩子函数既可以加工处理&#xff08;改变&#xff09;该函数的执行行为&#xff0c;也可以强制结束消息的传递。简单…

Vue23-props配置功能

Vue2&3-props配置功能 Vue2-props配置 功能&#xff1a;接收从其他组件传过来的数据&#xff0c;将数据从静态转为动态注意&#xff1a; 同一层组件不能使用props&#xff0c;必须是父组件传子组件的形式。父组件传数据&#xff0c;子组件接收数据。不能什么数据都接收&a…

虚幻C+++基础 day3

常见的游戏机制 Actor机关门 创建一个Actor类&#xff0c;添加两个静态网格与一个触发器 UBoxComponentUStaticMeshComponent 头文件&#xff1a; #include “Components/BoxComponent.h”#include “Components/StaticMeshComponent.h” TriggerDoor.h // Fill out your …

两个int(32位)整数m和n的二进制表达中,求有多少个位(bit)不同?

我先来讲一讲这道题的大概意思&#xff1a;假设我们输入的是 0 和 1: 0的32位二进制中为&#xff1a;000……0(32位) 1的32位二进制中为&#xff1a;000……1(32位) 那么就有一位不同。 方法一&#xff1a; 既然是二进制中&#xff0c;那么就是满二进一&#xff0c;就像…

操作系统·进程管理

2.1 前趋图和程序执行 2.1.1 前趋图 前趋图是一个有向无循环图&#xff0c;记为DAG&#xff0c;可用于描述程序/进程之间执行的前后关系&#xff0c;无循环关系可实现顺序执行。 2.1.2 程序的顺序执行 在计算机系统中只有一个程序在运行&#xff0c;这个程序独占系统中所有资…

基于FPGA的PCIe-Aurora 8/10音频数据协议转换系统设计阅读笔记

文章可知网下载阅读&#xff0c;该论文设计了一种 PC 到光纤模块&#xff08;基于Aurora的光纤传输&#xff09;的数据通路&#xff0c;成功完成了Aurora 以及 DDR 等模块的功能验证。 学习内容&#xff1a; 本次主要学习了Pcie高速串行总线协议、Aurora高速串行总线协议、DDR相…

Android 11.0 禁止弹出系统simlock的锁卡弹窗功能实现

1.前言 在11.0的系统rom产品定制化开发中,在关于定制sim卡定制机的一款产品中,需要实现simlock锁卡功能,在系统实现锁卡功能以后,在开机的过程中,或者是在插入sim卡 后,当系统检测到是禁用的sim卡后,就会弹出simlock锁卡弹窗,要求输入puk 解锁密码,功能需求禁用这个弹…

树莓派4B的测试记录(CPU、FFMPEG)

本文是用来记录树莓派 4B 的一些测试记录。 温度 下面记录中的风扇和大风扇是这样的&#xff1a; 为什么要用大风扇呢&#xff1f;因为小风扇在外壳上&#xff0c;气流通过外壳的珊格会有啸叫&#xff0c;声音不大但是很烦人&#xff0c;大风扇没这个问题&#xff0c;并且同样…

QMetaType和QVariant使用

描述 QMetaType和QVariant可以结合使用&#xff0c;用于在运行时确定数据类型。 QMetaType是Qt提供的用于管理各种数据类型的类&#xff0c;它可以帮助我们在运行时动态地创建、销毁、复制和比较数据类型。我们可以使用QMetaType来注册我们自己的数据类型&#xff0c;并为其提…

用于图像处理的高斯滤波器 (LoG) 拉普拉斯

一、说明 欢迎来到拉普拉斯和高斯滤波器的拉普拉斯的故事。LoG是先进行高斯处理&#xff0c;继而进行拉普拉斯算子的图像处理算法。用拉普拉斯具有过零功能&#xff0c;实现边缘岭脊提取。 二、LoG算法简述 在这篇博客中&#xff0c;让我们看看拉普拉斯滤波器和高斯滤波器的拉普…

【STM32】STM32的Cube和HAL生态

1.单片机软件开发的时代变化 1.单片机的演进过程 (1)第1代&#xff1a;4004、8008、Zilog那个年代&#xff08;大约1980年代之前&#xff09; (2)第2代&#xff1a;51、PIC8/16、AVR那个年代&#xff08;大约2005年前&#xff09; (3)第3代&#xff1a;51、PIC32、Cortex-M0、…

Python Selenium Headless:以 Headless 模式打开 Chrome 浏览器

本篇文章介绍了如何在 Python 中使用 Selenium 运行浏览器无头模式。 在 Python 中使用 Selenium 以无头模式运行 Chrome 浏览器 要说 headless 浏览器,你也可以称它们为真正的浏览器,只不过它们是在后台运行的; 您将无法在任何地方看到它们,但它们仍在后台运行。 在某些…

拓世科技集团打造数字人营销解决方案,为车企提供新的“增长担当”

汽车&#xff0c;已经渐渐融入了现代人的日常生活&#xff0c;从高端的身份标志转变为普罗大众的出行选择&#xff0c;它驶入了千家万户&#xff0c;成为了我们日常出行的可靠伙伴&#xff0c;见证着人们的生活故事和时代的变迁。 中国汽车市场的蓬勃发展引起了业内外的广泛关…

达梦数据库-Win10安装

目录结构 前言达梦数据库达梦数据库适用场景达梦数据库 PK MySQL达梦数据库安装数据库下载解压下载的压缩文件安装详细步骤安装关键节点配置 DM管理工具启动DM管理工具DM管理工具连接达梦数据库 参考链接 前言 达梦数据库Win10系统安装整理&#xff1b; 达梦数据库 达梦数据库…

Netty第三部

继续Netty第二部的内容 一、ChannelHandler 1、ChannelHandler接口 ChannelHandler是Netty的主要组件&#xff0c;处理所有的入站和出站数据的应用程序逻辑的容器&#xff0c;可以应用在数据的格式转换、异常处理、数据报文统计等 继承ChannelHandler的两个子接口&#xff…

uniapp踩坑之项目:隐藏显示密码功能

1.input组件的password设置为动态前面加:冒号&#xff1b; 2.动态切换眼睛图标使用:style //html <view> 密码&#xff1a;<input placeholder"请输入密码" :password"openPassword" type"text" placeholder-style"color:#e2e2e2;…

QT QStackedWidget

QStackedWidget是一个特殊的布局容器&#xff0c;它可以管理多个页面&#xff0c;并且只能显示其中一个页面。这些页面是QWidget或其派生类的实例&#xff0c;并通过调用addWidget()函数添加到堆栈中。 例如&#xff1a; #include <QWidgets> #include <QStackedWid…