单链表-Java实现

news2024/11/25 3:47:49

目录

概念

什么是链表?

为什么链表的头节点不能动,或者不能操作?

链表和数组的区别是什么?

实现

节点

单链表

末尾添加

遍历

按编号添加:

修改节点

删除

面试题

求单链表的长度

求单链表倒数第K个节点

求两个链表的公共节点,如果有多个,返回第一个。

单链表的反转

从尾到头打印单链表的节点

合并两个有序的单链表,合并后依然有序


概念

什么是链表?

链表是一种含有数据域和指针域的数据结构,以节点的方式来存储,在内存中是不连续的,分为带头节点的和不带头节点的。

为什么链表的头节点不能动,或者不能操作?

链表的操作都要基于头节点,如果头节点丢失,整个链表会丢失。

链表和数组的区别是什么?

链表在内存中是不连续的, 数组是连续的。

链表的插入和删除,效率要优于数组,数组的遍历和修改优于链表。

链表在空间上消耗两倍的数组内存。

链表支持动态扩容,数组在初始化的时候长度就固定了。


实现

节点

实现单链表之前,先构造一个链表节点HeroList,这里我们以漫威英雄为例,英雄角色有编号no,姓名name,性别sex,我们将no,name和sex定义为数据域,no为主键,唯一不可更改,方便我们进行修改和查找等操作。还需要定义一个next指针域,用来指向下一个节点。

下面我们通过Java语言实现节点:

//链表节点类
class HeroList {
    int no;
    String name;
    boolean sex;
    HeroList next;

    public HeroList(int no, String name, boolean sex) {
        this.no = no;
        this.name = name;
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "HeroList{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", sex=" + sex +
                '}';
    }
}

单链表

有了节点,我们可以通过next指针,将一个个节点串联,组装为一个单链表。这个单链表应该含有一个头节点,表示起始,以及各种操作函数,可以对这个单链表进行查找、修改、遍历、删除、新增等。

末尾添加

下面我们通过Java语言实现单链表的添加:

class SingleLinkedList {
    //我们需要定义一个head节点,表示链表的开始,head节点不能动,数据域不存放数据,丢失head节点,链表则会丢失
    HeroList head = new HeroList(0, "", false);


    //在末尾添加节点
    public void addAtEnd(HeroList hero) {
    //因为头节点,不能动,我们需要一个临时节点来操作
        HeroList temp = head;
    //需要遍历,找到末尾节点
        while (true) {
            if (temp.next == null) //到末尾了
                break;
    //temp后移
            temp = temp.next;
        }

    //循环结束,temp就是末尾节点
        temp.next = hero;
    }
}

遍历

Java语言实现单链表的遍历

    //链表的遍历
    public void listLinked() {
        //如果链表为null,无须遍历
        if (head.next == null) {
            System.out.println("链表为null");
            return;
        }
        //链表不为null,通过一个临时节点遍历链表
        HeroList temp = head.next;
        while (temp != null) {
            System.out.println(temp);
            temp = temp.next;
        }
    }

按编号添加:

Java语言实现单链表的按位添加

    //按编号添加节点,如果编号已存在,添加失败
    public void addByNo(HeroList hero){
        //1:需要一个临时节点temp来操作
        HeroList temp = head;
        //待添加的节点是否存在,默认不存在
        boolean flag  = false;
        //2:遍历单链表
        while (true){
            if(temp.next==null) {//找到末尾,没找到,插入到末尾
                break;
            }
            if(temp.next.no>hero.no)//找到待添加的位置了,是temp的后面
            {
                break;
            }
            if(temp.next.no==hero.no){//已存在,添加失败
                flag = true;
                break;
            }
            //temp后移
            temp = temp.next;
        }

        if(flag){
            System.out.printf("待添加的节点%d已存在\n",hero.no);
        }else{
            //此时,将hero.next指向temp.next;
            hero.next = temp.next;
            //再将temp.next指向hero
            temp.next = hero;
        }
    }

修改节点

Java语言实现单链表的修改

这里的修改指的是根据编号,修改节点的数据域。

 //修改节点
    public  void updateLinked(HeroList hero)
    {
         HeroList temp = head;
         //是否找到待修改的节点
         boolean flag = false;
         while (true){
             if(temp.next == null){//遍历到末尾了,还没找到
                 break;
             }
             if(temp.next.no == hero.no){//找到了,temp.next节点
                 flag = true;
                 break;
             }
             //temp后移
             temp = temp.next;
         }

         if(flag){
             temp.next.name = hero.name;
             temp.next.sex = hero.sex;
         }else
             System.out.println("待修改的节点不存在");

    }

删除

Java语言实现单链表的删除

根据节点编号删除单链表,如果单链表为null,则删除失败。

//根据编号删除节点
    public  void delByNo(int no){
        HeroList temp = head;
        if(temp.next==null){
            System.out.println("链表为null,无法删除");
            return;
        }
        //是否找到待删除的节点,默认没找到
        boolean flag = false;
        while (true){
            if(temp.next == null){//找到末尾了,还没找到
                break;
            }
            if(temp.next.no==no){//找到了
                flag = true;
                break;
            }
            temp= temp.next;
        }

        if(flag)
            temp.next = temp.next.next;
        else
            System.out.printf("待删除的节点不存在%d",no);
    }

面试题

求单链表的长度

    //1:求单链表的长度,或者单链表的有效长度
    //给定一个单链表的头节点,返回单链表的长度
    public static int getLength(HeroList head){
        int length = 0;
        if(head.next==null){
            return length;
        }
        //开始遍历
        HeroList temp = head;
        while (temp.next!=null){
            length++;
            temp = temp.next;
        }
        return length;
    }

求单链表倒数第K个节点

    //2:求单链表单数第k个结点
    //如果节点存在,返回节点,不存在返回null
    public static HeroList getKNode(HeroList head,int k){
        //求单链表倒数第K个节点,就是遍历到length-K位置的节点,用一个for循环
        //k的范围应该大于0,小于length
        int size = getLength(head);
        if(k>size||k<0){
            return null;
        }
        HeroList temp = head.next;
        for(int i = 0;i<size-k;i++){
            temp = temp.next;
        }
        return temp;
    }

}

求两个链表的公共节点,如果有多个,返回第一个。

    //给定2个单链表的头节点,求这两个单链表的公共部分,并且返回,如果没有公共部分,返回null
    public HeroList getPublicPart(HeroList head1,HeroList head2){
        //要找两个单链表的公共部分,首先要遍历,如何一次遍历,就找到公共节点呢?
        //这里的思路是链表A遍历到末尾后,指向链表B的头节点,链表B遍历到末尾后,指向链表A的头节点,这样子,2个链表的
        //速度一样,路程一样,当两个指针相遇的时候,就是公共部分的起始节点。如果循环,结束,没有相遇的指针,p1和p2都在末尾,
        //为null,直接返回即可。
        //代码如下:
        HeroList p1 = head1;
        HeroList p2 = head2;
        
        while (p1!=p2){
            p1 = (p1==null)?p2:p1.next;
            p2 = (p2==null)?p1:p2.next;
        }
        return p1;
    }

单链表的反转

    //3:单链表的反转
    public static void reverseLinked(HeroList head){
        //思路,
        //如果单链表为null或者节点数目为1,无需反转
        if(head==null||head.next==null)
            return;

        // 需要三个指针,第一个辅助节点cur,用来遍历头节点,指向head.next
        HeroList cur = head.next;
        //第二个指针,next,用来保存/备份cur节点的下一个节点,在操作过程中,不丢失原链表
        HeroList next;
        //第三个指针,reverse,新链表的头节点
        HeroList reverse = new HeroList(0,"",false);

        //开始遍历原链表
        while (cur!=null){
            //备份cur.next
            next = cur.next;
            //断开cur,并放到reverse.next的前面
            cur.next = reverse.next;
            //将cur链接到reverse的后面
            reverse.next = cur;
            //cur后移
            cur = next;
        }

        //原链表的头,指向reverse的下一个节点
        head.next = reverse.next;
    }

从尾到头打印单链表的节点

方式一:将单链表反转,然后遍历输出,不建议,会改变原有链表的结构

方式二:遍历原链表,压入栈,使其出栈。

    //4:从尾到头,打印单链表
    public static void printEtoFLinked(HeroList head){
        if(head.next==null)
            return;

        Stack<HeroList> stack  = new Stack<>();
        HeroList temp = head.next;
        while (temp!=null){
            stack.push(temp);
            temp = temp.next;
        }

        while (stack.size()>0){
            System.out.println(stack.pop());
        }
    }

合并两个有序的单链表,合并后依然有序

 //合并2个有序的单链表,合并后依然有序
    public static HeroList mergeLinked(HeroList hero1,HeroList hero2){
        HeroList temp1 = hero1.next;
        HeroList temp2 = hero2.next;
        //1第一步先判断
        if (temp1 == null && temp2 == null)
            return null;
        if (temp1 == null)
            return temp2;
        if (temp2 == null)
            return temp1;

        //2定义新链表的firstNode,LastNode;
        HeroList firstNode;
        HeroList lastNode;

        //3比较待合并链表的值,设置新链表的首节点和尾节点,并且temp后移
        if(temp1.no<temp2.no){
            firstNode = temp1;
            lastNode  = temp1;
            temp1 = temp1.next;
        }else {
            firstNode = temp2;
            lastNode  = temp2;
            temp2 = temp2.next;
        }

        //4开始循环,循环终止条件是temp1并且temp2不为null
        while (temp1!=null && temp2!=null){
            //循环的目的依次比较,将较小的节点添加到新链表的lastNode
            if(temp1.no<temp2.no){
                lastNode.next = temp1;
                lastNode = temp1;
                temp1 = temp1.next;
            }else{
                lastNode.next = temp2;
                lastNode = temp2;
                temp2 = temp2.next;
            }
        }
        //5循环结束,判断temp1或者temp2是否为null,将一方不为null的节点保存到新链表的lastNode
        if(temp1==null){
            lastNode.next = temp2;
        }else{
            lastNode.next = temp1;
        }

        return firstNode;
    }

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

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

相关文章

Qt关于hex转double,或者QByteArray转double

正常的00 ae 02 33这种类型的hex数据类型可以直接通过以下代码进行转换 double QDataConversion::hexToDouble(QByteArray p_buf) {double retValue 0;if(p_buf.size()>4){QString str1 byteArrayToHexStr(p_buf.mid(0,1));QString str2 byteArrayToHexStr(p_buf.mid(1,…

更安全,更高效的自学网络安全与黑客技术

学习网络安全&#xff08;黑客技术&#xff09; 网络安全是&#xff1a;黑客技术是&#xff1a;网络安全与黑客技术的关系&#xff1a;自学网络安全学习的误区和陷阱&#xff1a;学习网络安全前期需要准备...学习网络安全中期大致步骤&#xff1a;学习网络安全推荐的学习资料&a…

【电子通识】什么是异常分析中的A-B-A方法

工作有了一定的经验之后&#xff0c;在做问题分析的时候&#xff0c;经常会听到别人说把这个部品&#xff08;芯片/模块&#xff09;拿去ABA一下&#xff0c;看看跟谁走。那么对于新人来说是否就会问一个问题&#xff1a;什么是ABA呢&#xff1f; A-B-A 交换是一种简单直接的交…

华为OD七日集训第1期 - 按算法分类,由易到难,循序渐进,玩转OD(文末送书)

目录 一、适合人群二、本期训练时间三、如何参加四、7日集训第一期 ~ 华为OD初体验五、精心挑选21道高频100分经典题目&#xff0c;作为入门。第1天、逻辑分析第2天、字符串处理第3天、数据结构第4天、双指针第5天、递归回溯第6天、二分查找第7天、贪心算法 && 二叉树 …

【双指针】经典数组双指针题LeetCode

文章目录 27. 移除元素 简单283. 移动零 简单&#x1f525;167. 两数之和 II - 输入有序数组 中等11. 盛最多水的容器 中等&#x1f525;15. 三数之和 中等&#xff08;N数之和&#xff09;中等&#x1f525;42. 接雨水 困难 &#x1f525;26. 删除有序数组中的重复项 简单5. 最…

Qt快速学习(一)--对象,信号和槽

目录 1.Qt概述 1.1 什么是Qt 2.2 手动创建 2.3 pro文件 2.4 一个最简单的Qt应用程序 3 第一个Qt小程序 3.1 按钮的创建 3.2 对象模型&#xff08;对象树&#xff09; 3.3 Qt窗口坐标体系 4 信号和槽机制 4.1 系统自带的信号和槽 4.2 自定义信号和槽 4.3信号槽的拓展 4…

GSM/CDMA/VoLTE/VoIP通话

1.GSM(Global System for Mobile Communications) 本质是一种多址技术&#xff0c;将多个通话放入一段无线电频道的方法。特点是通过“时间划分”&#xff0c;称为时分多址。 2.CDMA(Code Division Multiple Access) 一种多址技术&#xff0c;将多个通话放入一段无线电频道的…

11_Redis经典五大类型源码及底层实现

Redis经典五大类型源码及底层实现 一、Redis数据类型的底层数据结构 SDS动态字符串双向链表压缩列表 zpilist哈希表 hashtable调表 skiplist整数集合 intset快速列表 quicklist紧凑列表 listpack 二、Redis源码地址 Github&#xff1a;https://github.com/redis/redis 三、…

Appium 2安装与使用java对Android进行自动化测试

文章目录 1、Appium 2.1安装1.1、系统要求1.2、安装Appium2.1服务1.3、安装UiAutomator2驱动1.4、安装Android SDK platform tools1.5、下载OpenJDK 2、Android自动代码例子2.1、安装Android自动化测试元素定位工具Appium Inspector2.2、编写android app自动化测试代码和使用ex…

Lemon8与中国各大社交平台的内容输出整合,将会掀起何种风浪?

近期,Lemon8迅速在北美地区展开了布局,短短几天的时间,下载量就冲到了美国APP下载总榜的前十,随后更是直登顶生活类APP首榜。作为字节跳动旗下的出海内容平台,一经问世后,就受到了大量用户的关注,并吸引了海外媒体以及营销人士的目光。那么Lemon8与中国各大社交平台的内容输出整…

机器学习笔记之优化算法(十六)梯度下降法在强凸函数上的收敛性

机器学习笔记之优化算法——梯度下降法在强凸函数上的收敛性 引言回顾&#xff1a;凸函数与强凸函数梯度下降法&#xff1a;凸函数上的收敛性分析 关于白老爹定理的一些新的认识梯度下降法在强凸函数上的收敛性收敛性定理介绍结论分析证明过程 引言 本节将介绍&#xff1a;梯度…

人工智能大模型加速数据库存储模型发展 行列混合存储下的破局

数据存储模型 ​专栏内容&#xff1a; postgresql内核源码分析手写数据库toadb并发编程toadb开源库 个人主页&#xff1a;我的主页 座右铭&#xff1a;天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物. 概述 在数据库的发展过程中&#xff0c;关…

【Linux】进程间通信之信号机制

文章目录 信号的概念信号的产生硬件产生&#xff08;按键盘中的按键&#xff09;软件产生kill函数kill命令abort函数raise函数 捕捉信号后的处理方式默认处理方式SIG_DFL忽略处理方式SIG_IGN自定义信号处理方式signal函数sigaciotn函数 信号的注册进程中的未决信号集&#xff0…

在python中通过调用dll来提高运行速度

1、前言 最近项目中需要录制键鼠命令&#xff0c;然后再通过注入的方式回放录制过程。一般来说&#xff0c;普通的一些点击命令完全可以通过python的一些包来完成键鼠模拟操作&#xff0c;比如通过pyautogui包。但是&#xff0c;鼠标移动过程中&#xff0c;如果采用频率很高的…

C++对象模型实验(clang虚函数表结构)

摘要&#xff1a;本科期间有对比过msvc&#xff0c;gcc&#xff0c;clang的内存布局&#xff0c;距今已经6-7年了&#xff0c;当时还是使用的c11。时间过得比较久了&#xff0c;这部分内容特别是内存对齐似乎C17发生了一些变化&#xff0c;因此再实践下C类模型。本文描述了C不同…

DuckDB Executor:物理计划构建Pipeline并执行(PipelineExecutor)

2023-03-20 duckdb-Push-Based Execution Model 如下SQL的物理计划执行 select 100(select 3), id from user where id (select id from score where id 1) Pipeline与MetaPipeline Pipeline是一串Op. MetaPipeline是pipeline组成的树 Executor构建MetaPipeline MetaPip…

【汇编语言】关于“段”的总结

文章目录 各种段三种段具体案例截图数据段、栈段、代码段同时使用不同段地址数据段、栈段、代码段同时使用一个段地址![在这里插入图片描述](https://img-blog.csdnimg.cn/45c299950ad949e3a90b7ed012b3a9ee.png) 各种段 1、基础 物理地址 段地址 x 16 偏移地址 2、做法 编…

Redis——主从复制+集群搭建(非哨兵)

主从复制 概念 主从复制&#xff0c;是指将一台Redis服务器的数据&#xff0c;复制到其他的Redis服务器。前者称为主节点(master/leader)&#xff0c;后者称为从节点(slave/follower); 数据的复制是单向的&#xff0c;只能由主节点到从节点。Master以写为主&#xff0c;Slave…

CentOS6.8图形界面安装Oracle11.2.0.1.0

Oracle11下载地址 https://edelivery.oracle.com/osdc/faces/SoftwareDelivery 一、环境 CentOS release 6.8 (Final)&#xff0c;测试环境&#xff1a;内存2G&#xff0c;硬盘20G&#xff0c;SWAP空间4G Oracle版本&#xff1a;Release 11.2.0.1.0 安装包&#xff1a;V175…

【C++奇遇记】构造函数 | 初始化列表

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集 数据库专栏 初阶数据结构 &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如…