数据结构【线性表篇】(二)

news2025/4/22 8:48:38

数据结构【线性表篇】(二)


文章目录

  • 数据结构【线性表篇】(二)
  • 前言
    • 为什么突然想学算法了?
    • 为什么选择码蹄集作为刷题软件?
  • 目录
  • 一、单链表
    • (一)、单链表的定义
    • (二)、单链表的建立
    • (三)、单链表的插入删除
    • (四)、单链表的查找
  • 二、主函数代码
  • 三、结语


前言

在这里插入图片描述

为什么突然想学算法了?

> 用较为“官方”的语言讲,是因为算法对计算机科学的所有分支都非常重要。 在绝大多数的计算机科学分支领域中,要想完成任何实质性的工作,理解算法的基础知识并掌握与算法密切相关的数据结构知识是必不可少的。
> 但从实际而言,是因为当下竞争压力逐渐增大,无论走哪一条路,都不免需要一些相对丰富的算法知识,是故,便产生了一个寒假巩固速成算法的计划,可能对于像我这种算法竞赛小白而言,几乎很难,但我仍然还是想尝试一下,毕竟,梦想还是要有的,万一实现了呢?~( ̄▽ ̄~)~

在这里插入图片描述


为什么选择码蹄集作为刷题软件?

码蹄集,是在全国高等学校计算机教学与产业实践资源建设专家委员会(TIPCC) 指导下建设的,其依托全国各大名校计算机系和清华大学出版社等单位的强大资源,旨在为计算机学习爱好者提供全面和权威的计算机习题。
.
在这里插入图片描述


目录

一、单链表

(一)、单链表的定义

参考代码

//单链表的定义
typedef struct LNode{                   //定义单链表结点类型
    int data;                           //每个节点存放一个数据元素
    struct LNode*next;                  //指针指向下一个节点
}LNode,*LinkList;
//增加一个新的结点:在内存中申请一个结点所需空间,并用指针p指向这个结点
LNode* p=(LNode*)malloc(sizeof(LNode));
//要表示一个单链表时,只需要声明一个头指针L,指向单链表的第一个结点
LinkList L; //声明一个指向单链表第一个结点的指针=LNode *L,但前者可读性更强

(二)、单链表的建立

//单链表的建立
//尾插法建立单链表
LinkList List_TailInsert(LinkList &L){      //正向建立单链表
    int x;                                  //设ElemType为整型
    L = (LinkList)malloc(sizeof(LNode));    //建立头结点,初始化空表
    LNode *s,*r=L;                          //r为表尾指针
    scanf("%d",&x);                  //输入9999表示结束
    while(x!=9999){
        s=(LNode *)malloc(sizeof(LNode));   //在r结点之后插入元素x
        s->data=x;
        r->next=s;
        r=s;                                //r指向新的表尾结构。永远保持r指向最后一个结点
        scanf("%d",&x);
    }
    r->next=NULL;                           //表尾指针置空
    return L;
}
//头插法建立单链表——重要应用:链表的逆置
LinkList List_HeadInsert(LinkList &L){      //逆向建立单链表
    LNode *s; int x;
    L=(LinkList)malloc(sizeof(LNode));      //创建头结点
    L->next=NULL;                           //初始为空链表
    scanf("%d",&x);                  //输入9999表示结束
    while(x != 9999){
        s=(LNode*)malloc(sizeof(LNode));    //创建新结点
        s->data=x;
        s->next=L->next;
        L->next=s;                          //将新结点插入表中,L为头指针
        scanf("%d",&x);
    }
    return L;
}
//创建不带头结点的单链表
//初始化一个空的单链表
bool InitList(LinkList &L){
    L = NULL;                               //空表,暂时还没有任何结点(防止脏数据)
    return true;
}

bool Empty(LinkList L){                     //判断单链表是否为空
    return (L==NULL);
}
/初始化一个单链表(带头结点)
bool InitListWithNode(LinkList &L){
    L = (LNode *) malloc(sizeof(LNode));    //分配一个头结点
    if(L==NULL)                             //内存不足,分配失败
        return false;
    L->next = NULL;                         //头结点之后暂时还没有节点
    return true;
}

//判断单链表是否为空(带头结点)
bool EmptyWithNode(LinkList L){
    if(L->next==NULL)
        return true;
    else
        return false;
}

//------------------------------------------------
//带头结点,写代码更方便
//不带头结点,写代码更麻烦
// (1)对第一个数据节点和后续数据结点的处理需要用不同的代码逻辑
// (2)对空表和非空表的处理需要用不同的代码逻辑

(三)、单链表的插入删除

//插入
//按位序插入(带头结点)
//在第i个位置插入元素e(带头结点)
bool ListInsertWithNode(LinkList &L,int i,int e){
    if(i<1)
        return false;
    LNode *p;                               //指针p指向当前扫描到的结点
    int j=0;                                //当前p指向的是第几个结点
    p=L;                              //L指向头结点,头结点是第0个结点(不存数据)
    while(p!=NULL && j<i-1){                //循环找到第i-1个结点
        p=p->next;
        j++;
    }
    if(p==NULL)                             //i值不合法
        return false;
    LNode *s = (LNode *) malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;                            //将结点s连到p之后
    return true;                            //插入成功
} //平均时间复杂度O(n)
//按位序插入(不带头结点)
//插入、删除第1个元素时,需要改变头指针L
bool ListInsert(LinkList &L,int i,int e){
    if(i<1)
        return false;
    if(i==1){ //插入第1个结点的操作与其他结点操作不同
        LNode *s = (LNode *) malloc(sizeof(LNode));
        s->data = e;
        s->next = L;
        L = s;                              //头指针指向新结点
        return true;
    }
    LNode *p;                               //指针p指向当前扫描的结点
    int j=1;                                //当前p指向的是第几个结点
    p=L;                                    //p指向第1个结点(注意:不是头结点)
    while(p!=NULL && j<i-1){                //循环找到第i-1个结点
        p=p->next;
        j++;
    }                                       //自此往下,=return InsertNextNode(p,e);
    if(p==NULL)                             //i值不合法
        return false;
    LNode *s = (LNode *) malloc(sizeof(LNode));
    s->data = e;
    s->next = p->next;
    p->next = s;
    return true;                            //插入成功
}
//指定结点的后插操作
//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p,int e){
    if(p==NULL)
        return false;
    LNode *s = (LNode *) malloc(sizeof(LNode));
    if(s==NULL)                             //内存分配失败
        return false;
    s->data = e;                            //用结点s保存数据元素e
    s->next = p->next;
    p->next = s;                            //将结点s连到p之后
    return true;
} //时间复杂度O(1)
//指定结点的前插操作
//前插操作(法一):在p结点之前插入元素e
bool InsertPriorNode(LNode *p,int e){
    if(p==NULL)
        return false;
    LNode *s = (LNode *)malloc(sizeof(LNode));
    if(s==NULL)                             //内存分配失败
        return false;
    s->next=p->next;
    p->next=s;                              //新结点s连到p之后
    s->data=p->data;                        //将p中元素复制到s中
    p->data=e;                              //p中元素覆盖为e
    return true;
}

//前插操作(法二):在p结点之前插入元素e
bool InsertPriorNode(LNode *p,LNode *s){
    if(p==NULL || s==NULL)
        return false;
    s->next=p->next;
    p->next=s;                              //新结点s连到p之后
    int temp = p->data;                     //交换数据域部分
    p->data=s->data;
    s->data=temp;
    return true;
}
//删除操作
//删除表L中第i个位置的元素,并用e返回删除元素的值

//按位序删除(带头结点)
bool ListDeleteWithNode(LinkList &L,int i,int e){
    if(i<1)
        return false;
    LNode *p;                               //指针p指向当前扫描到的结点
    int j=0;                                //当前p指向的是第几个结点
    p=L;                                    //L指向头结点,头结点是第0个结点(不存数据)
    while(p!=NULL && j<i-1){                //循环找到第i-1个结点
        p=p->next;
        j++;
    }
    if(p==NULL)                             //i值不合法
        return false;
    if(p->next==NULL)                       //第i-1个结点之后已无其他结点
        return false;
    LNode *q=p->next;                       //令q指向被删除结点
    e = q->data;                            //用e返回元素的值
    p->next=q->next;                        //将*q结点从链中“断开”
    free(q);                                //释放结点的存储空间
    return true;
}
//删除指定结点p
bool DeleteNode(LNode *p){
    if(p==NULL)
        return false;
    LNode *q=p->next;                       //令q指向*p的后继结点
    p->data=p->next->data;                  //和后继结点交换数据域
    p->next=q->next;                        //将*q结点从链中“断开”
    free(q);                                //释放后继结点的存储空间
    return true;
}
//单链表的局限性:
// (1)无法逆向检索,有时候不太方便
// (2)如果p是最后一个结点,只能从表头开始依次寻找p的前驱,时间复杂度O(n)

(四)、单链表的查找

//查找
//按位查找,返回第i个元素(带头结点)
LNode *GetElemWithNode(LinkList L,int i){
    if(i<0)
        return NULL;
    LNode *p;                               //指针p指向当前扫描到的结点
    int j=0;                                //当前p指向的是第几个结点
    p=L;                                    //L指向头结点,头结点是第0个结点(不存数据)
    while(p!=NULL && j<i){                  //循环找到第i个结点
        p=p->next;
        j++;
    }
    return p;
} //平均时间复杂度O(n)

//王道书版本:
LNode *GetElemWithNodeCS(LinkList L,int i){
    int j=1;
    LNode *p=L->next;
    if(i==0)
        return L;
    if(i<1)
        return NULL;
    while(p!=NULL && j<i){                  //循环找到第i个结点
        p=p->next;
        j++;
    }
    return p;
} //平均时间复杂度O(n)

//按值查找,找到数据域==e的结点
LNode * LocateElem(LinkList L,int e){
    LNode *p = L->next;
    int i=0;
    //从第1个结点开始查找数据域为e的结点
    while(p!=NULL && p->data !=e){
        p=p->next;
        i++;
    }
    return p;                               //找到后返回该结点指针,否则返回NULL
} //平均时间复杂度O(n)

int LocateElemI(LinkList L,int e){
    LNode *p = L->next;
    int i=1;
    //从第1个结点开始查找数据域为e的结点
    while(p!=NULL && p->data !=e){
        p=p->next;
        i++;
    }
    if(p==NULL) return 0;
    else return i;                          //找到后返回该元素位置,如果没找到,则返回0
} //平均时间复杂度O(n)

二、主函数代码

//求表的长度
int Length(LinkList L){
    int len=0;                              //统计表长
    LNode *p = L;
    while(p->next != NULL){
        p = p->next;
        len++;
    }
    return len;
}

//------------------------------------------------------------
void printListWithNode(LinkList L){         //带头结点
    LNode *p=L;
    p=p->next;
    while(p!=NULL){
        printf("%d ",p->data);
        p=p->next;
    }
    printf("\n");
}

void printList(LinkList L){                  //不带头结点
    LNode *p=L;
    while(p!=NULL){
        printf("%d ",p->data);
        p=p->next;
    }
    printf("\n");
}

int main(){
    LinkList L;                              //声明一个指向单链表的指针
    InitListWithNode(L);                  //初始化一个空表(带头结点)
    //InitList(L);                          //初始化一个空表(不带头结点)

    //插入
    ListInsertWithNode(L,1,3);      //带头结点
    ListInsertWithNode(L,2,4);
    ListInsertWithNode(L,3,5);
    printListWithNode(L);
//
//    if(ListInsert(L,1,3))                  //不带头结点
//        printList(L);

    //删除
    ListDeleteWithNode(L,2,5);
    printf("删除后的序列为:\n");
    printListWithNode(L);

    //查找
    LNode *p;
    p=GetElemWithNode(L,2);                         //按位查找
    printf("第2个元素值为:%d\n",p->data);
    int i = LocateElemI(L,4);                //按值查找
    if(i==0) printf("不存在该元素\n");
    else printf("元素4所在位置为:%d\n",i);

    //求单链表长度
    int len = Length(L);
    printf("该单链表的长度为:%d\n",len);

    return 0;
}

三、结语

感谢大家一直以来的不断支持与鼓励,码题集题库中的进阶塔350题正在逐步更新,之后会逐步跟进星耀,王者的题,尽请期待!!!
同时,也希望这些题能帮助到大家,一起进步,祝愿每一个算法道路上的“苦行僧”们,都能够历经磨难,终成正果,既然选择了这条路,走到了这里,中途放弃,岂不是太过可惜?

另附中国计算机学会的杰出会员、常务理事轩哥博士的B站视频讲解链接https://space.bilibili.com/518554541/?spm_id_from=333.999.0.0,供大家更好的进行学习与刷题~( ̄▽ ̄~)~

愿你的结局,配得上你一路的颠沛流离。
在这里插入图片描述

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

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

相关文章

电表通讯协议DLT645-2007编程

1、协议 电表有个电力行业推荐标准《DLT645-2007多功能电能表通信协议》&#xff0c;电表都支持&#xff0c;通过该协议读取数据&#xff0c;不同的电表不需要考虑编码格式、数据地址、高低位转换等复杂情况&#xff0c;统一采集。 不方便的地方在于这个协议定义得有点小复杂…

【数据结构与算法】字符串匹配(头歌习题)【合集】

目录 第1关&#xff1a;实现朴素的字符串匹配任务描述相关知识编程要求评测说明完整代码 第2关&#xff1a;实现KMP字符串匹配任务描述相关知识编程要求评测说明完整代码 第3关&#xff1a;【模板】KMP算法任务描述相关知识C STL容器string1、string的定义2、string中内容的访问…

计算机网络-动态路由

网络层协议&#xff1a;ip&#xff0c;ospf&#xff0c;rip&#xff0c;icmp共同组成网络层体系 ospf用于自治系统内部。 一个路由器或者网关需要能够支持多个不同的路由协议&#xff0c;以适应不同的网络环境。特别是在连接不同自治系统的边缘路由器或边界网关的情况下&#…

第2课 使用FFmpeg读取rtmp流并用openCV显示视频

本课对应源文件下载链接&#xff1a; https://download.csdn.net/download/XiBuQiuChong/88680079 这节课我们开始利用ffmpeg和opencv来实现一个rtmp播放器。播放器的最基本功能其实就两个:显示画面和播放声音。在实现这两个功能前&#xff0c;我们需要先用ffmpeg连接到rtmp服…

蓝桥杯嵌入式KEY

1.按键原理图 2.按键GPIO引脚设置成输入&#xff0c;上拉模式 3.设置TIM4时钟源为外部时钟源 PSC为80-1 Period为10000-1 打开NVIC 中断时间为10ms 4.在bsp文件中添加interrupt.c文件 5.按键单击代码 6.长按键 7.按键过程和显示过程

动态规划 典型例题

总结 动态规划的的四个解题步骤是&#xff1a; 定义子问题写出子问题的递推关系确定 DP 数组的计算顺序空间优化&#xff08;可选&#xff09; from functools import cache cache #缓存&#xff0c;避免重复运算 def dfs(i)->int:if 终止: return 0 #具体返回什么值要看…

在线尺码计算

在线衣服尺码计算 尺码不确定的话&#xff0c;可以填写身高、体重生成可以参考的尺码还是不错的 工具简介 选购时请综合参考尺码表中的各项参数&#xff0c;这有助您选择到更好的尺码。 该尺码计算工具仅供参考&#xff0c;测量脚时请注意用适当力度轻踩水平面上。因测量方法不…

Tomcat和Servlet

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Tomcat是什么&#xff1f;1.1下载&#xff1a;1.2 tomcat是什么1.3启动服务器&#xff1a; 二.部署三、Servlet3.1创建项目3.2引入依赖pom.xml的所有代码 3…

electron——查看electron的版本(代码片段)

electron——查看electron的版本(代码片段)1.使用命令行&#xff1a; npm ls electron 操作如下&#xff1a; 2.在软件内使用代码&#xff0c;如下&#xff1a; console.log(process) console.log(process.versions.electron) process 里包含很多信息&#xff1a; process详…

Python装饰器的专业解释

装饰器&#xff0c;其实是用到了闭包的原理来进行操作的。 单个装饰器&#xff1a; 以下是一个简单的例子&#xff1a; def outer(func):print("OUTER enter ...")def wrapper(*args, **kwargs):print("调用之前......")result func(*args, **kwargs)p…

4.31 构建onnx结构模型-Tile

前言 构建onnx方式通常有两种&#xff1a; 1、通过代码转换成onnx结构&#xff0c;比如pytorch —> onnx 2、通过onnx 自定义结点&#xff0c;图&#xff0c;生成onnx结构 本文主要是简单学习和使用两种不同onnx结构&#xff0c; 下面以 Tile 结点进行分析 方式 方法一…

用Xshell连接虚拟机的Ubuntu20.04系统记录。虚拟机Ubuntu无法上网。本机能ping通虚拟机,反之不能。互ping不通

先别急着操作&#xff0c;看完再试。 如果是&#xff1a;本机能ping通虚拟机&#xff0c;反之不能。慢慢看到第8条。 如果是&#xff1a;虚拟机不能上网&#xff08;互ping不通&#xff09;&#xff0c;往下一直看。 系统是刚装的&#xff0c;安装步骤&#xff1a;VMware虚拟机…

DevOps系列 之 Python与Java互相调用的案例

Python和Java是两种非常流行的编程语言。Python是一种解释型语言&#xff0c;而Java则是一种编译型语言。两者都有广泛的应用&#xff0c;尤其是在测试领域。在本文中&#xff0c;我们将讨论如何使用Python测试Java源代码&#xff0c;Java如何调用Python脚本。 单元测试 单元…

redis的基本使用

一、 Redis简介 Redis是一个基于内存的 key-value 结构数据库。Redis是一款采用key-value数据存储格式的内存级NoSQL数据库&#xff0c;重点关注数据存储格式&#xff0c;是key-value格式&#xff0c;也就是键值对的存储形式。与MySQL数据库不同&#xff0c;MySQL数据库有表、…

WEB 3D技术 three.js 雾 基础使用讲解

本文 我们说一下 雾 在three.js中有一个 Fog类 它可以创建线性雾的一个效果 她就是模仿现实世界中 雾的一个效果 你看到远处物体会组件模糊 直到完全被雾掩盖 在 three.js 中 有两种雾的形式 一种是线性的 一种是指数的 个人觉得 线性的会看着自然一些 他是 从相机位置开始 雾…

Unity坦克大战开发全流程——开始场景——音效数据逻辑

开始场景——音效数据逻辑 从这里开始到后面的三小节我们都将干一件很重要的事——数据存储&#xff0c;只有实现了数据存储才能在再次进入游戏时保持游戏数据不被丢失。 类图分析&#xff1a;数据管理类是一个大类&#xff0c;它其中关联了两个类&#xff08;这两个类都是数据…

2023年终总结 —— 我和CSDN相遇的第一年之“技术学习和个人成长的回顾与展望”

​ ​ &#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 &#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 &#x1f38a;对2023的总结与回顾&#x1f38a; &#x1f3c5;获奖记录 &#x1f4da;学…

test mock-03-wiremock 模拟 HTTP 服务的开源工具 flexible and open source API mocking

拓展阅读 test 之 jmockit-01-overview jmockit-01-test 之 jmockit 入门使用案例 mockito-01-overview mockito 简介及入门使用 PowerMock Mock Server ChaosBlade-01-测试混沌工程平台整体介绍 jvm-sandbox 入门简介 wiremock WireMock是一个流行的开源工具&#xf…

蚂蚁实习一面面经

蚂蚁实习一面面经 希望可以帮助到大家 tcp建立连接为什么要三次握手&#xff1f; 三次握手的过程 注意&#xff1a;三次握手的最主要目的是保证连接是双工的&#xff0c;可靠更多的是通过重传机制来保证的 所谓三次握手&#xff0c;即建立TCP连接&#xff0c;需要客户端和…

Centos7部署Keepalived+lvs服务

IP规划&#xff1a; 服务器IP地址主服务器20.0.0.22/24从服务器20.0.0.24/24Web-120.0.0.26/24Web-220.0.0.27/24 一、主服务器安装部署keepalivedlvs服务 1、调整/proc响应参数 关闭Linux内核的重定向参数&#xff0c;因为LVS负载服务器和两个页面服务器需要共用一个VIP地…