链表-单向链表

C语言实现单向链表 本章使用C语言实现了数据结构中的单向链表,难度也不高,但值得作为学习数据结构的人去亲自实现一下。 阅读详情

链表 (Linked List)

1.概述:

1、 链表是以结点的方式来存储,是链式存储
2、 每个结点包含data域,next域;指向下一个结点
3、 链表的各个结点不一定是连续地址存放
4、链表分带头结点的链表和没有头结点的链表,根据实际的需求来确定
在这里插入图片描述

2.单向链表的创建、把结点添加到链表尾部(尾插法)

缺点:只能根据添加的前后顺序来输出显示

2.1 定义一个结点类

代码如下:

// 定义HeroNode,每个HeroNode的实例对象就是一个结点
class HeroNode{
    public int no;
    public String name;
    public String nickname;
    public HeroNode next;  // 指向下一个结点

    public HeroNode(int no, String name, String nickname) {
        this.no = no;
        this.name = name;
        this.nickname = nickname;
    }

    // 为了显示方便,重写toString方法
    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                ", nickname='" + nickname + '\''  +
                '}';
    }
}

2.2 定义链表类,以及添加和显示的功能

添加(创建):
1、先创建一个head头结点,作用是表示单链表的头
2、后面我们每添加一个结点,就直接加入到链表的最后

遍历:
通过一个辅助变量遍历,帮助遍历整个链表

代码如下:

// 定义SingleLinkedList管理我们的英雄
class SingleLinkedList{
    // 先初始化一个头结点,头结点不要动,不存放具体的数据
    private HeroNode head= new HeroNode(0,"","");

    // 添加节点到单向链表
    // 思路,当不考虑编号顺序时
    // 1、找到当前链表的最后节点  2、将最后这个结点的next指向新的结点
    public void add1(HeroNode heroNode){
        // 因为head结点不能动,因此需要一个辅助遍历temp
        HeroNode temp =head;
        // 遍历链表,找到最后结点
        while (true){
            // 找到链表的最后
            if (temp.next==null){
                break;
            }
            // 如果没有找到最后,将temp后移
            temp=temp.next;
        }
        // 当推出while循环时,temp就只想了链表的最后
        temp.next=heroNode;
    }

    // 显示链表【遍历】
    public void showlist(){
        // 判断链表是否为空
        if(head.next==null){
            System.out.println("链表为空");
            return;
        }
        // 因为头结点,不能动,因此要一个辅助遍历temp来遍历
        HeroNode temp=head.next;
        while (true){
            // 判断是否到链表最后
            if (temp==null){
                break;
            }
            //输出结点信息
            System.out.println(temp);
            // 将temp后移,一定要小心
            temp=temp.next;
        }
    }
}

2.3 测试自定义链表,以及添加和显示的功能

代码如下:

public class SingleLinkedListDemo {
    public static void main(String[] args) {
        // 进行测试
        // 先创建结点
        HeroNode sj = new HeroNode(1, "宋江", "及时雨");
        HeroNode ljy = new HeroNode(2, "卢俊义", "玉麒麟");
        HeroNode wy = new HeroNode(3, "吴用", "智多星");
        HeroNode lc = new HeroNode(4, "林冲", "豹子头");

        // 创建单向链表
        SingleLinkedList singleLinkedList = new SingleLinkedList();
        // 加入
        singleLinkedList.add1(sj);
        singleLinkedList.add1(ljy);
        singleLinkedList.add1(wy);
        singleLinkedList.add1(lc);

        // 显示
        singleLinkedList.showlist();
    }
}

3.单向链表的创建、把结点添加到链表中间(指定结点后插法)

优势:可以无视添加的先后顺序,根据自己定义的节点编号(no)大小顺序来显示

说明:

需要按照编号的顺序添加
1、首先找到新添加的结点的位置,是通过辅助变量temp(指针),遍历搞定。
2、(新的结点.next)=temp.next
3、将temp.next=新结点

代码改动如下:

// 第二种方式在添加结点时,根据顺序排名将结点插入到指定位置
    // 如果有这个排名,则添加失败,并给提示
    public void add2(HeroNode heroNode){
        // 因为head结点不能动,因此需要一个辅助temp 遍历到要添加的位置
        // 因为单链表,找的temp位于添加位置的前一个结点,否则插入不了(指定位置后插)
        HeroNode temp =head;
        boolean flag=false;// 表示添加的结点的编号是否存在,默认false
        // 遍历到指定位置
        while (true){
            if (temp.next==null){ //到链表最后
                break;
            }
            if (temp.next.no>heroNode.no){  // 位置找到,就在temp的后面
                break;
            }else if (temp.next.no==heroNode.no){ // 希望添加的结点已经存在
                flag=true;
                break;
            }
            temp=temp.next;
        }
        if (flag){    // flag为true时不可以添加
            System.out.printf("结点的编号%d已存在不可以再添加 ",heroNode.no);
        }else{
        // 插入到链表中 temp后(指定位置后面)
         heroNode.next=temp.next;
         temp.next=heroNode;
        }
    } 

测试代码改动如下:

// 第二种方式添加  (根据no来排列)
        singleLinkedList.add2(sj);
        singleLinkedList.add2(lc);
        singleLinkedList.add2(wy);
        singleLinkedList.add2(ljy);

4.—添加修改指定编号结点信息的方法

修改节点的信息,根据no编号来修改,即no编号不能改 说明:根据newHeroNode 的no来修改

添加代码如下:

// 修改节点的信息,根据no编号来修改,即no编号不能改
    // 说明:根据newHeroNode 的no来修改
    public void updata(HeroNode newHeroNode){
        if(head.next==null){
            System.out.println("链表为空");
            return;
        }
        HeroNode temp=head.next;
        boolean flag=false;
        while (true){
            if(temp==null) {
                break;  // 到链表的最后 已经遍历完链表了
            }
            if(temp.no==newHeroNode.no){
                flag=true;  // 找到了
                break;
            }
            temp=temp.next;
        }
        // 根据flag判断是否找到要修改的结点
        if (flag){
            temp.name= newHeroNode.name;
            temp.nickname=newHeroNode.nickname;
        }else {
            System.out.printf("没有找到编号%d的结点 ",newHeroNode.no);
        }

   }

测试代码如下:

// 测试修改节点的代码
        HeroNode newheroNode = new HeroNode(2, "小卢", "玉麒麟~~");
        singleLinkedList.updata(newheroNode);

        // 显示
        System.out.println("修改后的情况...");
        singleLinkedList.showlist();

5.添加删除结点的方法

从单链表中删除一个结点的思路==
1、先找到需要删除的这个节点(根据no判断)的前一个结点temp
2、temp.next=temp.next,next
3、被删除的节点,将不会有其他引用指向,将会被垃圾回收机制回收。

添加代码如下:

//根据no值来判断删除
   public void del(int no){
       HeroNode temp=head;
       boolean flag=false;  //  标识是否找到
       while (true){
           if (temp.next==null){ //到最后
               break;
           }
           if (temp.next.no==no) {
               // 找到待删除结点的前一个结点temp
               flag = true;
               break;

           }
           temp=temp.next; // temp后移,继续遍历
       }
       if (flag){
           temp.next=temp.next.next;
       }else {
           System.out.printf("要删除的编号%d的结点不存在\n",no);
       }
   }

测试代码如下:

        // 删除一个结点
        singleLinkedList.del(1);
        System.out.println("删除后的情况...");
        singleLinkedList.showlist();

6.单向链表面试题

6.1求单链表中有效结点的个数

概述:

方法:获取到单链表有效结点的个数(有头结点的要去掉)
head 链表的头结点 return是返回的有效结点的个数

代码如下:

public static int getLength(HeroNode head){
        if(head.next==null){  // 如果头结点下一个为null返回0
            return 0;
        }
        int length=0;
        HeroNode temp=head;
        while (true){
            if (temp.next==null){
                break;
            }
            temp=temp.next;
            length++;
        }
        return length;
    }

// 测试一下统计结点个数

 System.out.println("有效的结点个数为:" + SingleLinkedList.getLength(singleLinkedList.getHead()));

6.2查找单链表中倒数第k个结点

思路说明:

1、编写一个方法,时接受一个index
2、index表示是倒数第index个结点
3、先把链表遍历一遍,得到链表长度m,然后再遍历(m-index) 使要查找的结点对应的next(下一个)就是要查找的倒数k个结点

实现代码如下:

public  HeroNode  findneedIndex(int index){
        if(head.next==null){
            return null;  // 没有找到
        }
        int m=getLength();   // 获取链表长度
        HeroNode temp=head;
        if(index<=0 || index>m ){
			return null;
		}
        for (int i=1;i<=(m-index);i++){
            temp=temp.next;
        }
        return temp.next;
    }

// 测试一下查找倒数第k个结点

System.out.println("输出的倒数第k个结点是:"+ singleLinkedList.findneedIndex(1));      

6.3单链表的反转(头插法)

思路如下:

1、先定义一个头结点reverseHead=new HeroNode(0,“”,“”);—一个只有头结点的新链表
2、从头到尾遍历原来的链表,每遍历一个结点,就将其取出,并放在新的链表reverseHead的最前端。

next = temp.next;// 保存temp后的那个结点,后面移位要使用

temp.next = reversehead.next; // 取下的temp指向新链表头结点指向的结点(null)。

reversehead.next = temp; // 将新链表的头结点指向取下的temp结点

temp = next; // 把temp移到保存再next中它后面的那个结点

实现代码如下:

public void reverseHead(){
        if (head.next==null || head.next.next==null){
            return;
        }
        HeroNode temp=head.next;
        HeroNode next =null; // 指向当前结点【cur】的下一个结点
        HeroNode reversehead= new HeroNode(0,"","");
        // 从头到尾遍历原来的链表,没遍历一个结点,就将其取出,
        // 并放在新的链表reverseHead的最前端。
        while (temp!=null) {
            next = temp.next;// 保存temp后的那个结点,后面移位要使用
            temp.next = reversehead.next; // 取下的temp指向新链表头结点指向的结点(null)。
            reversehead.next = temp; // 将新链表的头结点指向取下的temp结点
            temp = next;  // 把temp移到保存再next中它后面的那个结点
        }
        // 将head.next指向reversehead.next,实现头结点的替换
        head.next=reversehead.next;
    }

测试如下:

// 测试单链表的反转功能
        System.out.println("原来的单链表");
        singleLinkedList.showlist();

        System.out.println("反转后的单链表");
        singleLinkedList.reverseHead();
        singleLinkedList.showlist();

6.4从尾到头打印单链表(反向遍历 / stack栈)

思路分析:

方式一:先将单链表进行翻转操作,然后在遍历即可(问题是会破坏原来单链表的结构,不可取)
方式二:可以利用栈这个数据结构,将各个结点压入到栈中,然后利用栈的先进后出的特点,就实现了逆序打印的效果。

单向链表 双向链表 / 将最后一个节点的 next 指向新节点。= NULL) { // 找到链表的最后一个节点。删除 3 后的链表: 从前向后打印链表: 2 -> 1 -> 4 -> NULL。从前向后打印链表: 2 -> 1 -> 3 -> 4 -> NULL。从后向前打印链表: 4 -> 3 -> 1 -> 2 -> NULL。 阅读详情

相关推荐

【爬虫】Python实现爬取淘宝商品信息(超详细)

项目基于Python的第三方库Selenium模拟浏览器运行、PyQuery解析和操作HTML文档,获取淘宝平台中某类商品的详细信息(商品标题、价格、销量、商铺名称、地区、商品详情页链接、商铺链接等),并基于第三方库openpyxl建立、存储于Excel表格中。# 全局变量count = 1 # 写入Excel商品计数# 启动ChromeDriver服务# 关闭自动测试状态显示 // 会导致浏览器报:请停用开发者模式# 把chrome设为selenium驱动的浏览器代理;# 窗口最大化。

qq_46315152的博客 4万+

链表-----单向链表详解

玩单链表的时候一定要注意区分头指针和头结点,在链表的初阶学习时,老师可能会对第一个结点直接取地址传过去,在无头单链表中,头指针和第一个结点重名,这就导致了当时学链表的时候很疑惑为啥一会儿传第一个结点的地址,一会儿传第一个结点的地址的地址。菜就多练!

weixin_51134816的博客 2577

西门子1200数据块BD详解

定义 DB(Data Block)是用于存储用户数据的区域,分为两种类型:核心作用 四、DB块的访问方式 1. 全局DB访问 符号访问(优化块): 绝对地址访问(非优化块):(假设SetPoint占用2字节) 2. 背景DB访问 与FB关联后自动生成,通过FB调用时传递: 五、高级功能与注意事项 数据块的初始化运行时修改DB数据块的下载常见问题 通过合理使用DB块,可显著提升程序的可读性和可维护性。建议优先启用优化块访问并使用符号名编程。如何使用DB数据块 数据块用于存储程序数据。因此,数据块

weixin_51020122的博客 3429

数据结构—单向链表(详解)

基于C语言的链表基础,包括概念,链表的初始化,插入,删除,查找等操作。

梅山 1万+

手动以及使用torch.nn实现前馈神经网络实验

手动以及使用torch.nn实现前馈神经网络 手动实现前馈神经网络解决上述回归、二分类、多分类任务 利用torch.nn解决上述回归、二分类、多分类任务 在多分类任务中使用至少三种不同的激活函数 对多分类任务中的模型评估隐藏层层数和隐藏单元个数对实验结果的影响

m0_52910424的博客 9372

5G中的RedCap

5G中的redcap

大家好,我是码农老gou,一名专注于编程技术的程序员。在这个博客中,我将与大家分享我在工作和学习中的经验、见解以及一些实用的技术干货。 2527

单向链表SingleLinkedList

本文案例仅仅使用Java语言实现单向链表的一些简单的增删改查,完成反转单向链表,以及借助栈逆序遍历单向链表等功能。

weixin_66598341的博客 1646

cursor AI代码编辑器IDE对接deepseek模型api;字节ai编辑器trae

参考: https://www.cursor.com/ https://platform.deepseek.com/https://www.cursor.com/下载安装后,注册账号登录即可 再高级里选择设置 再模型这注册模型: 模型名称一定要填正确,url地址填好,最后填上秘钥验证

weixin_42357472的博客 1万+

数据结构与算法---单向链表

单向链表的详细讲解(附完整版)

weixin_73602725的博客 2108

如何使用Github创建一个完全免费的个人网站

摘要: 本文详细介绍如何利用Github Pages免费搭建个人静态网站,适合零基础用户。首先需注册Github账号并创建特定命名的仓库(格式:用户名.github.io),然后通过网页或命令行创建index.html文件作为网站首页。完成后可通过"仓库设置- Pages"获取网站链接。文章还包含GitHub Desktop的安装使用、代码提交指南及常见问题自检方法,并说明即使Github被墙也可迁移至国内平台(如码云)。整个过程无需编程基础,仅需15分钟即可完成基础网站搭建。

安德洛夫 1514

【C++】开源:cpp-httplib HTTP协议库配置与使用

cpp-httplib HTTP协议库配置与使用

DevFrank的博客 5538

链接表操作:遍历、插入和删除

什么是链表?链表是一种线性数据结构,包括一系列相连的结点。在这里,每个节点都存储数据和下一个节点的地址。例如:链表有多种类型:单链表、双链表和循环链表。这里仅介绍单链表。

ntr851217的博客 2012

WCK Operation (WCK 操作)

LPDDR6 SDRAM采用双时钟系统(WCK和CK),其中WCK频率是CK的两倍。为确保数据正确传输,需通过WCK2CK同步操作使两种时钟对齐。LPDDR6支持两种同步模式:Auto-sync off模式和WCK Always on模式,可通过MR22寄存器选择。同步操作由特定命令(Read/Write/MRR等)触发,需在满足特定时序参数(如tWCKENL、tWCKPRE等)后完成。同步前必须完成WCK2CK训练,且不同操作(读取/写入/CAS)有各自的时序要求。该机制确保数据在正确时钟相位下传输,是L

李家小院 649

【数据结构】之单向链表、双端(单向)链表、循环(单向)链表

单向链表、双端(单向)链表、循环(单向)链表示意(简)图: 单向链表:只有一个指针指向头结点。 双端(单向)链表:有一个指针指向头结点,还有一个指针指向尾节点。 循环(单向)链表:指向形成一个闭环。 双端(单向)链表的Java实现(简单示例): 注:单向链表、双端(单向)链表、循环(单向)链表的实现思路几乎一样,这里以实现双端(单向)链表示例。 /** * 双端链表 简...

JustryDeng 1900

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

单向链表及单向链表操作

链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。相比于线性表顺序结构,操作复杂。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而线性表和顺序表相应的时间复杂度分别是O(logn)和O(1)

2401_84360682的博客 659

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

单向链表Python

链表是一种常见的数据结构,用于存储和组织数据。它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。 链表相对于数组的优势在于灵活性。由于链表的节点并不一定连续存储在内存中,因此可以动态地插入和删除节点,而不需要移动其他节点。然而,链表的缺点是访问特定位置的节点较慢,需要从头节点开始遍历到指定位置。

泰敢人辣的博客 3993

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

单向链表和双向链表区别_单向链表

基本定义单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量指向列表中的下一个结点;链表是由结点构成,head指针指向第一个成为表头结点,而终止于最后一个指向-NULL的指针。链表优点单个结点创建非常方便,普通的线性内存通常在创建的时候就需要...

weixin_39618806的博客 1199

002单向链表

数据结构__单向链表

你好啊!猿道友 1541

单向、双向链表

链表 一、介绍 1、介绍 ​ 链表是一种非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列节点(链表中每一个元素称为节点)组成,节点可以在运行时动态生成。每个节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域 (1)单向链表(单链表)是链表的一种,它由节点组成,每个节点都包含下一个节点的指针 (2)双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据节点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链

大树 3249

单向链表的反转

<br />昨天看优快云的一个文章提到,某公司面试时问到单向链表的反转问题,有好多程序员答不出来。以前我也没做过类似的题目,试着写了一下。<br />问题描述:已知一个单向链表,写一个函数,使得该链表的方向反转,即头变尾,尾变头,指示方向相反。<br />分析:该问题可以有两种方法,一是交换首尾两个节点的数据,而不改变其内存的存储结构,二是改变所有节点的指向下一个节点的指针。显然第二种方法更加有效。<br /> <br /> /×链表的定义和一些操作*/ typedef struct list {

guoyang1007的专栏 1万+

单向链表结构

本文简要介绍了单向链表的结构以及实现了一个单向链表类

qq_59750520的博客 971

数据结构——链表和单向链表

(1)定义链表是一种基本的数据结构,它由一系列节点组成,每个节点包含一个值和指向下一个节点的指针节点如下图所示:与数组不同,链表中的节点不一定是连续的存储空间,因此可以有效地利用内存空间,而不需要预先知道数据的数量,不擅长随机访问(要遍历)(3)优缺点优点:不要求大片连续空间,改变容量方便;可以动态的添加和删除节点缺点:不方便可随机存取,要耗费一定空间存放指针。

2301_81699298的博客 2059

C语言之单向链表

1,单向链简洁。 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过顺序读取从头部开始;链表是使用指针进行构造的列表;又称为结点列表,因为链表是由一个个结点组装起来的;其中每个结点都有指针成员变量指列表中的下一个结点; ​ 列表是由结点构成,由head指针指向第一个成为表头的结点而终止于最后一个指向nuLL的指针;2,例子要求: 根据示例代码中的例子,完成单向链表(...

csdn's blog 1万+

单向链表的创建

/链表的建立,就相当于一个结点不断尾插/头插的过程/ //1.0正向建链 #include&lt;stdio.h&gt; #include&lt;stdlib.h&gt; #define N 5 typedef struct node{ int data; struct node *next; }ElemSN; ElemSN *creatlink(int a[]) { ElemSN *h,*...

qq_42727102的博客 915

单向链表

一定要从新节点出发,指向后面的节点,然后将前驱节点指向字节。需要使用一个遍历指针,将每一个节点进行遍历一遍,如果该指针指向的节点不为空,就访问其数据域,向后偏移。3> 注意:需要将要删除的节点先标记一下,头节点的指针,指向第二个节点后,将标记的节点释放。3> 注意:必须找到要插入位置的节点的前驱节点,将前驱节点当作头节点,进行头插操作。3> 注意:需要找到要删除的节点的前驱节点,将其当作头节点,进行头删逻辑。6、头节点:虚设的一个节点,数据域不存放数据元素,可以存放链表的长度。

没有百宝袋的哆啦A梦的博客 1383

单向链表的遍历

/链表的遍历和数组类似,就是跑链表/ //输出单向链表尾结点的值 #include<stdio.h> #include<stdlib.h> #define N 5 typedef struct node{ int data; struct node *next; }ElemSN; ElemSN *Creatlink(int a[]) { ElemSN *h,*tail...

qq_42727102的博客 1718
上一篇: 稀疏数组和队列
下一篇: 链表-双向链表
AX_Chu
博客等级 码龄6年 13粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值