数据结构----链表

news2024/11/17 1:54:41

一丶概念

          链表又称单链表、链式存储结构,用于存储逻辑关系为“一对一”的数据。
          和顺序表不同同,使用链表存储数据,不强制要求数据在内存中集中存储,各个元素可以分散存储在内存中。

二丶特点

         特点:内存不连续,通过指针进行连接
         解决: 长度固定的问题,插入删除麻烦的问题
         逻辑结构:线性结构

         存储结构:链式存储
         操作:增删改查
struct node
{
    int data;   //数据域:存储数据
    struct node *next;    //指针域:存储下一个节点的地址
};

三丶单向链表

1.分类

        有头链表:存在一个头节点,头节点数据域无效,指针域有效。
        无头链表:每一个节点的数据域和指针域都有效。

2.有头单向链表

        存在一个头节点,数据域无效,指针域有效

#include <stdio.h>
#include<stdlib.h>
typedef int datatype;
typedef struct node
{
    int data;//数据域
    struct node *next;//指针域
} node_t, *node_p;
int main(int argc, char const *argv[])
{
    node_t A={1,NULL};//输入数据
    node_t B={2,NULL};
    node_t C={3,NULL};
    node_t D={4,NULL};
    A.next=&B;
    B.next=&C;
    C.next=&D;
    node_p p;
    //头指针指向头节点
    node_t S = {'\0',&A};
    p=H.next;
    while(p!=NULL)
    {
        printf("%d ",p->data);
        p=p->next;
    }
    printf("\n");
    return 0;
}

3.无头单向链表

所有节点的指针域和数据域都有效

#include <stdio.h>
#include <stdlib.h>
typedef char datatype;
typedef struct node
{
    datatype data;     //数据域用来存数据
    struct node *next; //指针域用来存下一个节点的地址
} node_t, *node_p;

// node_t A; //等同于 struct node A;
// node_p p; //等同于 struct node *p;

int main(int argc, char const *argv[])
{
    //1.定义4个节点
    node_t A = {'a', NULL};
    node_t B = {'b', NULL};
    node_t C = {'c', NULL};
    node_t D = {'d', NULL};

    //2.连接四个节点
    A.next = &B; //连接A和B
    B.next = &C;
    C.next = &D;

    //3.定义一个头指针指向第一个节点
    node_p p = &A;

    //4. 通过指针遍历无头单向链表
    while (p != NULL)
    {
        printf("%c ", p->data); //打印节点中的数据域 a b c d
        p = p->next;            //让p指向下一个节点
    }
    printf("\n");

    return 0;
}

链表尾插法练习

写一个有头单向链表,用于保存输入的学生成绩,实现一输入学生成绩就创建一个新的节点,将成绩保存起来。再将该节点链接到链表的尾,直到输入-1结束。

要求:每个链表的节点由动态内存分配得到 , 也就是用malloc。

过程:

1.  malloc申请空间link_node_t大小作为头节点

2.  将新节点放到链表尾部

#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node
{
    int data;//数据域存放数据
    struct node *next;//指针域记录下一个结点地址
} node_t, *node_p;
void ShowLinklist(node_p p)//打印数据
{
    while(p!=NULL)
    {
    printf("%d ",p->data);
    p=p->next;
    }
    printf("\n");
}
int main(int argc, char const *argv[])
{
    int score = 0;
    // 创建一个头节点
    node_p p_head = (node_p)malloc(sizeof(node_t));
    if (NULL == p_head)//容错判断
    {
        printf("malloc err");
        return -1;
    }
    //让头指针的指针域置空
    p_head->next = NULL;
    //创建一个尾节点
    node_p p_tail = (node_p)malloc(sizeof(node_t));
    if (NULL == p_head)
    {
        printf("p_tail malloc err");
        return -1;
    }
    p_tail = p_head;//让尾节点指向头节点
    while (1)
    {
        //循环输入成绩
        scanf("%d", &score);
        //输入-1时停止结束循环
        if (score == -1)
            break;
        //新建一个节点p_new
        node_p p_new = (node_p)malloc(sizeof(node_t));
        if (NULL == p_new)//容错判断
        {
            printf("p_new malloc err");
            return -1;
        }
        p_new->data = score; //将数据存入新的节点
        p_new->next = NULL;//让新的节点的指针域置空
        p_tail->next = p_new;//让尾节点连接到新的节点
        p_tail=p_new;//更新尾节点
    }
    node_p p = p_head->next;
    ShowLinklist(p);
    return 0;
}

4.有头单向链表函数操作

插入的思想

1. 先遍历找到要插入节点的前一个节点,假设这个节点为A;A的下一个节点为B;将C插入A与B之间;
2.先让C的指针域指向B;
3.再让A的指针域指向C;

注意:顺序不可以调换

int InsertLinklist(node_p p, int post, int data) // 插入数据
{
    if (post < 0 || post > StrlenLinklist(p))
    {
        printf("Insert eerr");
        return -1;
    }
    for (int i = 0; i < post; i++) // 让p指向插入位置post的前一个节点
        p = p->next;
    node_p p_new = (node_p)malloc(sizeof(node_t)); // 创建一个新的节点
    if (NULL == p_new)                             // 容错判断
    {
        printf("p_new malloc err");
        return -1;
    }
    p_new->data = data;    // 让新节点的数据域等于新的数据
    p_new->next = p->next; // 指针域等于插入位置的地址
    p->next = p_new;       // 前一个节点的指针域等于新节点的地址
    return 0;
}

删除的思想

      1.先遍历找到要删除节点的前一个节点,假设为A;

      2、找一个临时指针指向要删除的节点;
      3、  将A的指针域指向删除节点的下一个节点;
      4、  释放被删除节点

int DeleteLinklist(node_p p, int post) // 删除函数
{
    if (post < 0 || post >= StrlenLinklist(p))
    {
        printf("Insert eerr");
        return -1;
    }
    for (int i = 0; i < post; i++) // 让p指向删除位置post的前一个节点
        p = p->next;                                 
    node_p p1 = p->next; // 新定义一个结构体指针用来存放删除位置的地址
    p->next = p1->next;  // 让被删除位置的前一个的指针域等于被删除位置后一个节点的地址
    free(p1);            // 将被删除指针释放,指针置空
    p1 = NULL;
}


转置的思想:

(1) 将头节点与当前链表断开,断开前保存下头节点的下一个节点,保证后面链表能找得到,定义一个q保存头节点的下一个节点,断开后前面相当于一个空的链表,后面是一个无头的单向链表
(2) 遍历无头链表的所有节点,将每一个节点当做新节点插入空链表头节点的下一个节点(每次插入的头节点的下一个节点位置)

void ReverseLinkList(node_p p)
{

    node_p temp = NULL;//临时保存q下一个节点的地址
    //断开前,保存头节点的下一个节点的地址
     node_p q = p->next;//指向头节点的下一个节点(相当于无头单向链表的头指针)
    //1.断头,断开链表
    p->next = NULL;
    //2.遍历无头单向链表
    while (q != NULL)
    {
        //暂时存放q的下一个节点,防止链表丢失
        temp = q->next;
        //头插到有头单向链表头节点的后面
        q->next = p->next;
        p->next = q;
        //将q重新指向之前的无头单向链表,指向此时的第一个节点
        q=temp;
    }

完整的单链表操作

#include <stdio.h>
#include <stdlib.h>
typedef int datatype;
typedef struct node
{
    int data;          // 数据域存放数据
    struct node *next; // 指针域记录下一个结点地址
} node_t, *node_p;
node_p CreateEpLinkist() // 创建一个空的有头单向链表
{
    node_p p = (node_p)malloc(sizeof(node_t)); // 开辟节点空间大小
    if (NULL == p)
    {
        printf("CreatEpLinklist err");
        return NULL;
    }
    p->next = NULL; // 初始化头结点
    return p;
}
int StrlenLinklist(node_p p)//计算单链表长度
{
    int len = 0;
    while (p->next != NULL)
    {
        p = p->next;
        len++;
    }
    return len;
}
int InsertLinklist(node_p p, int post, int data) // 插入数据
{
    if (post < 0 || post > StrlenLinklist(p))
    {
        printf("Insert eerr");
        return -1;
    }
    for (int i = 0; i < post; i++) // 让p指向插入位置post的前一个节点
        p = p->next;
    node_p p_new = (node_p)malloc(sizeof(node_t)); // 创建一个新的节点
    if (NULL == p_new)                             // 容错判断
    {
        printf("p_new malloc err");
        return -1;
    }
    p_new->data = data;    // 让新节点的数据域等于新的数据
    p_new->next = p->next; // 指针域等于插入位置的地址
    p->next = p_new;       // 前一个节点的指针域等于新节点的地址
    return 0;
}
int DeleteLinklist(node_p p, int post) // 删除函数
{
    if (post < 0 || post >= StrlenLinklist(p))
    {
        printf("Insert eerr");
        return -1;
    }
    for (int i = 0; i < post; i++) // 让p指向删除位置post的前一个节点
        p = p->next;                                 
    node_p p1 = p->next; // 新定义一个结构体指针用来存放删除位置的地址
    p->next = p1->next;  // 让被删除位置的前一个的指针域等于被删除位置后一个节点的地址
    free(p1);            // 将被删除指针释放,指针置空
    p1 = NULL;
}
void ModifyLinklist(node_p p, int post, int data) // 修改函数
{
    for (int i = 0; i <= post; i++) // 让指针指向要修改的节点位置
        p = p->next;
    p->data = data; // 指针域等于新的数据
}
void SearchLinklist(node_p p, int data)//查找数据
{
    int i = 0;
    p = p->next;
    while (p != NULL)
    {
        if (p->data == data)
        {
            printf("%d\n", i);//打印第一个相同数据的下标
            break;
        }
        p = p->next;
        i++;
    }
}
void ClearLinklist(node_p p)//清空链表
{
    while(StrlenLinklist(p)!=0)
    {
        DeleteLinklist(p,0);//删除第一个节点
    }
}
void ShowLinklist(node_p p)// 打印数据
{
    while (p->next)// 当指针p的指针域为空时停止循环
    {
        p = p->next;
        printf("%d ", p->data);
    }
    printf("\n");
}
void ReverseLinkList(node_p p)//链表转置
{

    node_p temp = NULL;//临时保存q下一个节点的地址
    //断开前,保存头节点的下一个节点的地址
     node_p q = p->next;//指向头节点的下一个节点(相当于无头单向链表的头指针)
    //1.断头,断开链表
    p->next = NULL;
    //2.遍历无头单向链表
    while (q != NULL)
    {
        //暂时存放q的下一个节点,防止链表丢失
        temp = q->next;
        //头插到有头单向链表头节点的后面
        q->next = p->next;
        p->next = q;
        //将q重新指向之前的无头单向链表,指向此时的第一个节点
        q=temp;
    }
    
}
int IsEpLinklist(node_p p)
{
    return p->next == NULL;
}
int main(int argc, char const *argv[])
{
    node_p p = CreateEpLinkist(); // 创建一个空的有头单向链表
    InsertLinklist(p, 0, 1);// 进行插入数据
    InsertLinklist(p, 1, 2);
    InsertLinklist(p, 2, 3);
    InsertLinklist(p, 3, 4);
    InsertLinklist(p, 4, 5);
    InsertLinklist(p, 5, 6);
    ShowLinklist(p);// 打印数据
    DeleteLinklist(p, 0);// 删除数据
    ShowLinklist(p);// 打印数据
    ModifyLinklist(p, 0, 0); // 修改数据
    ShowLinklist(p);// 打印数据
    SearchLinklist(p, 2);
    ReverseLinkList(p);
    ShowLinklist(p);// 打印数据
    ClearLinklist(p);
    if(IsEpLinklist(p))
        printf("IsEpLinkList\n");
    free(p);
    p =NULL;
    return 0;
    return 0;
}

5.单向循环链表

四丶总结:

顺序表和单向链表比较:
             (1).顺序表在内存当中连续存储的(数组),但是链表在内存当中是不连续存储的,通过指针将数据链接在一起
            (2).顺序表的长度是固定的,但是链表长度不固定
            (3).顺序表查找方便,但是插入和删除麻烦,链表,插入和删除方便,查找麻烦

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

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

相关文章

《SPSS零基础入门教程》学习笔记——02.数据管理

文章目录 2.1 连续变量的离散化2.2 自动重编码、编秩与数值计数2.3 几个常用过程2.4 多个数据文件的操作2.5 数据字典2.6 数据核查&#xff08;1&#xff09;数据验证模块&#xff08;2&#xff09;数据检验 2.7 数据准备 计算新变量&#xff08;转换 -> 计算变量&#xff0…

VueUse 基于 Vue 3 Composition API 的高质量 Hooks 库

VueUse 是什么? VueUse 是基于 Vue 3 Composition API 的高质量 Hooks 库。例如获取滚动的距离 VueUse 官网:VueUse | VueUse VueUse 什么使用? 1、通过npm安装 VueUse npm i @vueuse/core 2、搜索需要使用的函数,例如搜索 useScroll 滚动 3、使用useScroll 滚动函数 …

使用RKNN在Orange Pi 5 (RK3588s) 上部署推理PPO深度学习模型

文章目录 一、前言1️⃣、Orange Pi 是什么&#xff1f;2️⃣、PPO 是什么&#xff1f;3️⃣、RKNN 是什么&#xff1f;3️⃣、ONNX 是什么&#xff1f; 二、项目简介三、部署流程1️⃣、PPO 网络结构2️⃣、PPO 输出模型&#xff0c;模型转换&#xff0c;以及对比检查3️⃣、.…

httplib库:用C++11搭建轻量级HTTP服务器

目录 引言 一. httplib库概述 二. httplib核心组件 2.1 数据结构 2.2 类和函数 2.3 服务器搭建 ​编辑 结语 引言 在现代软件开发中&#xff0c;HTTP服务是网络应用的基础。对于需要快速搭建HTTP服务器或客户端的场景&#xff0c;使用成熟的第三方库可以极大提高开发效…

微软运行库全集合:一站式解决兼容性问题

开发者在部署应用程序时经常遇到因缺少运行库而引发的兼容性问题。为了解决这一问题&#xff0c;电脑天空推荐微软常用运行库合集&#xff0c;一个集成了微软多个关键运行库组件的软件包。 &#x1f4da; 包含组件概览&#xff1a; Visual Basic Virtual Machine&#xff1a;…

电销机器人助力企业节约成本提升业绩

电销系统机器人 的出现对企业来说不但仅是提高一点工作效率这么简单。首先从拨打电话上来看&#xff0c;电销系统机器人每日能够拨打几千通、上万通电话无上线&#xff0c;都可自行设置&#xff0c;并且并不会感觉到累&#xff0c;更不会由于被挂掉电话而影响心情&#xff0c;这…

KNN算法-opencv的运用

文章目录 opencv介绍与安装KNN算法中opencv的运用1.数据介绍2.图片处理3.图像切分与重组4.分配标签5.模型构建与训练6.预测结果7.模拟测试8.代码及详注 opencv介绍与安装 OpenCV&#xff08;Open Source Computer Vision Library&#xff0c;开源计算机视觉库&#xff09;是一…

ShareSDK Twitter

创建应用 1.登录Twitter控制台并通过认证 2.点击Developer Portal进入Twitter后台 3.点击Sign up for Free Account创建应用 4.配置应用信息 以下为创建过程示例&#xff0c;图中信息仅为示例&#xff0c;创建时请按照真实信息填写&#xff0c;否则无法正常使用。 权限申请…

智能安全守护,寺庙安全用电解决方案

在四川省蓬溪县城北&#xff0c;高峰山以其千年的历史沉淀和独特的文化风貌&#xff0c;默默诉说着道教与佛教交融的传奇。然而&#xff0c;2017年5月31日凌晨的一声巨响&#xff0c;打破了这里的宁静&#xff0c;一场突如其来的大火&#xff0c;让这座承载着无数信徒信仰与梦想…

10步搞定Python爬虫从零到精通!

学习Python网络爬虫可以分为以下几个步骤&#xff0c;每一步都包括必要的细节和示例代码&#xff0c;以帮助你从零开始掌握这一技能。 第一步&#xff1a;理解网络爬虫基础 什么是网络爬虫&#xff1f; 网络爬虫是一种自动化程序,用来从互联网上收集数据.它通过发送 HTTP 请求…

大学生科创项目在线管理系统的设计与实现

TOC springboot267大学生科创项目在线管理系统的设计与实现 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电…

爬虫案例4——爬取房天下数据

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正 任务&#xff1a;从房天下网中爬取小区名称、地址、价格和联系电话 目标网页地址&#xff1a;https://newhouse.fang.com/house/s/ 一、思路和过程 目标网页具体内容如下&#xff1a; ​​​​ …

揭秘面试必备:高频算法与面试题全面解析

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版和持续更新见高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言…

Web安全:SqlMap工具

一、简介 sqlmap 是一款开源的渗透测试工具&#xff0c;可以自动化进行SQL注入的检测、利用&#xff0c;并能接管数据库服务器。它具有功能强大的检测引擎,为渗透测试人员提供了许多专业的功能并且可以进行组合&#xff0c;其中包括数据库指纹识别、数据读取和访问底层文件系统…

SystemUI手势操作隐藏显示导航栏

在Android 12中&#xff0c;通过SystemUI手势操作来隐藏和显示导航栏主要涉及对系统UI的定制和编程控制。以下是一些实现这一功能的方法&#xff1a; 第一类. 使用WindowInsetsController Android 12引入了一个新的WindowInsetsController类&#xff0c;它允许开发者更好地控…

加速科技精彩亮相2024中国(深圳)集成电路峰会

8月16日&#xff0c;2024中国&#xff08;深圳&#xff09;集成电路峰会&#xff08;简称“ICS2024峰会”&#xff09;在深圳如期开展&#xff0c;为行业带来一场技术盛宴。在这场盛会中&#xff0c;加速科技携2款核心产品——ST2500EX、ST2500E重磅亮相&#xff0c;凭借领先的…

【leetcode详解】特殊数组II : 一题代表了一类问题(前缀和思想)

前缀和的优势 给定一个数组&#xff0c;前缀和的特点在于&#xff0c;任意给出一对始末位置&#xff0c;能够用O(1)的时间复杂度得到始末位置之间所有元素的某种关系。 题型分析 这道题目正是“给出始末位置&#xff0c;检测其中元素特点”那一类&#xff0c;那我们就想&#…

【机器学习西瓜书学习笔记——概率图模型】

机器学习西瓜书学习笔记【第十四章】 第十四章 概率图模型概率图模型分类14.1 隐马尔可夫模型贝叶斯网络马尔科夫链隐马尔科夫模型 14.2 马尔可夫随机场( M R F MRF MRF)马尔可夫场定理算法原理概率推理参数学习算法对比 14.3 条件随机场( C R F CRF CRF)优缺点优点缺点 链式条…

Redis -LFU(Least Frequently Used,最少使用频率)缓存淘汰算法

在 Redis 的 LFU&#xff08;Least Frequently Used&#xff0c;最少使用频率&#xff09;缓存淘汰算法中&#xff0c;lru 字段被拆分成两部分&#xff1a;高 16 位存储 ldt&#xff08;Last Decrement Time&#xff09;&#xff0c;低 8 位存储 logc&#xff08;Logistic Coun…

【图像特效系列】卡通特效的实践 | 包含代码和效果图

目录 一 卡通特效 代码 效果图 图像特效系列主要是对输入的图像进行处理,生成指定特效效果的图片。图像素描特效会将图像的边界都凸显出来;图像怀旧特效是指图像经历岁月的昏暗效果;图像光照特效是指图像存在一个类似于灯光的光晕特效,图像像素值围绕光照中心点呈圆形范…