【数据结构】单链表的基本操作 (C语言版)

news2024/11/24 8:03:48

目录

一、单链表

1、单链表的定义:

2、单链表的优缺点:

二、单链表的基本操作算法(C语言)

1、宏定义

2、创建结构体

3、初始化

4、插入

4、求长度

5、清空

6、销毁 

7、取值

8、查找

9、删除

10、头插法创建单链表

11、尾插法创建单链表

三、单链表的全部代码(C语言)

四、运行结果


一、单链表

1、单链表的定义:

 单链表是一种链式存储的线性表,它用一组地址任意的存储单元来存放线性表中的数据元素。每个节点包含两个部分:数据域和指针域。数据域用于存储数据元素,指针域则存储下一个节点的地址。单链表的第一个节点称为头结点,最后一个节点称为尾结点。

单链表是一种链式存取的数据结构,用一组地址任意的存储单元来存放线性表中的数据元素。

每个节点包含两个部分:数据域和指针域。数据域用于存储数据元素,指针域则存储下一个节点的地址。链表中的数据是以结点来表示的,每个结点的构成包括元素(数据元素的映像)和指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。链表中的每个结点在内存中不是按顺序排列的,而是通过指针链接在一起。单链表的第一个节点称为头结点,最后一个节点称为尾结点。

与顺序表相比,单链表的优点在于插入和删除操作方便,时间复杂度较低,但随机访问和空间利用率不如顺序表。在实际应用中,单链表通常作为其他数据结构的子结构,如哈希表的桶、图的邻接表等。

单链表定义了节点的基本结构,包括数据元素和指向下一个节点的指针。节点的插入和删除操作涉及指针的修改,而非直接修改节点内容。由于其非连续性的特性,链表无法像数组一样随机访问任意元素,而只能从头到尾依次访问。因此,对于需要频繁插入和删除元素的应用场景,单链表是一种高效的数据结构。

2、单链表的优缺点:

单链表的优点:

  1. 插入和删除操作方便:只需修改指针即可,不需要移动大量元素。
  2. 动态分配内存:可以根据需要开辟内存空间,避免了顺序表中的空间浪费问题。

单链表的缺点:

  1. 存储密度低:以节点为单位存储,不支持随机访问,查找较为麻烦。
  2. 空间利用率低:每个节点需要额外的空间来存储指针,导致空间浪费。
  3. 查找效率低:由于链表在内存中不连续,需要从头节点开始逐个节点遍历,时间复杂度较高。

二、单链表的基本操作算法(C语言)

1、宏定义
#define OK 1
#define ERROR 0

typedef char ElemType;
typedef int Status;
2、创建结构体
typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;
3、初始化
//单链表初始化
Status InitList(LinkList &head){
    head=new LNode;
    head->next=NULL;
    return OK;
}
4、插入
  1. 创建一个新的结点。
  2. 将新结点的数据域置为所需插入的数据。
  3. 根据插入位置的不同,将新结点的指针域指向插入位置的后一个结点。如果是头部插入,则将新结点的指针域指向头结点;如果是尾部插入,则将新结点的指针域指向空;如果是中间插入,则将新结点的指针域指向插入位置的后一个结点。
  4. 将插入位置前一个结点的指针域修改为指向新结点。如果是头部插入,则将头结点的指针域修改为指向新结点;如果是尾部插入,则将尾结点的指针域修改为指向新结点;如果是中间插入,则将插入位置前一个结点的指针域修改为指向新结点。
//插入
Status ListInsert(LinkList &head,int i,ElemType e){
    LinkList p=head;
    int j=0;
    while (p && (j<i-1)){
        p=p->next;
        ++j;
    }
    if (!p||j>i-1){
        return ERROR;
    }

    LNode *s=new LNode;
    s->data=e;
    s->next=p->next;
    p->next=s;

    return OK;
}
4、求长度
//求单链表长度
Status GetLinkListLength(LinkList head){
    LinkList p=head->next;
    int length=0;
    while (p){
        p=p->next;
        length++;
    }
    return length;
}
5、清空

//清空
Status ClearLinkList(LinkList &head){
    LinkList p = head->next;
    LinkList q;
    while(p){
        q = p;
        p = p->next;
        delete q;
    }
    head->next = NULL;
    return OK;
}
6、销毁 

//销毁
Status DestoryLinkList(LinkList &head){
    LinkList p;
    while(head){
        p = head;
        head = head->next;
        delete p;
    }
    return OK;
}
7、取值
//取值
Status GetLinkList(LinkList head,int i,ElemType &e){
    LinkList p = head->next;
    int j = 0;
    while (p && j<i){
        p=p->next;
        j++;
    }
    if (!p || j>i){
        return ERROR;
    }
    e=p->data;

    return OK;
}
8、查找
//查找用函数返回查找元素的位置
int LocateLinkListElem(LinkList head,ElemType e){
    LinkList p=head->next;
    int j=1;
    while (p && (p->data != e)){
        p=p->next;
        j++;
    }
    if(p==NULL){
        return 0;
    }
    return j;
}
9、删除
  1. 找到要删除的结点的前一个结点。
  2. 将前一个结点的指针域修改为指向要删除的结点的下一个结点。
  3. 释放要删除的结点的存储空间。

//删除
Status ListDelete(LinkList &head,int i,ElemType &e){
    LinkList p=head;
    int j=0;
    while ((p->next) && (j<i-1)){
        p=p->next;
        ++j;
    }
    if (!(p->next)||j>i-1){
        return ERROR;
    }
    LinkList q=p->next;
    e=q->data;
    p->next=q->next;
    delete q;
    return OK;
}
10、头插法创建单链表
//头插法创建单链表
void CreateList_H(LinkList &head,int n){
    head=new LNode;
    head->next=NULL;
    for(int i=0;i<n;++i){
        LNode *p=new LNode;
        ElemType cin='a';
        cin>>p->data;
        p->next=head->next;
        head->next=p;
    }
}
11、尾插法创建单链表
//尾插法创建单链表
void CreateList_R(LinkList &head,int n){
    head=new LNode;
    head->next=NULL;
    LNode *r=head;
    for(int i=0;i<n;++i){
        LNode *p=new LNode;
        ElemType cin='a';
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}

三、单链表的全部代码(C语言)

#include <stdio.h>

#define OK 1
#define ERROR 0

typedef char ElemType;
typedef int Status;

typedef struct LNode{
    ElemType data;
    struct LNode *next;
}LNode,*LinkList;

//单链表初始化
Status InitList(LinkList &head){
    head=new LNode;
    head->next=NULL;
    return OK;
}

//功能菜单
int choice() {
    printf("==================================\n");
    printf("         单链表操作功能菜单          \n");
    printf("1、插入元素  2、查询表长  3、按位查找\n");
    printf("4、按值查找  5、删除元素  6、销毁链表\n");
    printf("7、清空链表  8、批量插入  9、结束程序\n");
    printf("10、头插法创建单链表11、尾插法创建单链表\n");
    printf("==================================\n");
    return 0;
}


//插入
Status ListInsert(LinkList &head,int i,ElemType e){
    LinkList p=head;
    int j=0;
    while (p && (j<i-1)){
        p=p->next;
        ++j;
    }
    if (!p||j>i-1){
        return ERROR;
    }

    LNode *s=new LNode;
    s->data=e;
    s->next=p->next;
    p->next=s;

    return OK;
}

//求单链表长度
Status GetLinkListLength(LinkList head){
    LinkList p=head->next;
    int length=0;
    while (p){
        p=p->next;
        length++;
    }
    return length;
}

//销毁
Status DestoryLinkList(LinkList &head){
    LinkList p;
    while(head){
        p = head;
        head = head->next;
        delete p;
    }
    return OK;
}

//清空
Status ClearLinkList(LinkList &head){
    LinkList p = head->next;
    LinkList q;
    while(p){
        q = p;
        p = p->next;
        delete q;
    }
    head->next = NULL;
    return OK;
}

//取值
Status GetLinkList(LinkList head,int i,ElemType &e){
    LinkList p = head->next;
    int j = 0;
    while (p && j<i){
        p=p->next;
        j++;
    }
    if (!p || j>i){
        return ERROR;
    }
    e=p->data;

    return OK;
}


//查找用引用型参数返回查找元素的位置
//LNode *LocateLinkList(LinkList head,ElemType e,Status &j){
//    LinkList p=head->next;
//    j=1;
//    while (p && p->data!=e){
//        p=p->next;
//        j++;
//    }
//    return p;
//}
//查找用函数返回查找元素的位置
int LocateLinkListElem(LinkList head,ElemType e){
    LinkList p=head->next;
    int j=1;
    while (p && (p->data != e)){
        p=p->next;
        j++;
    }
    if(p==NULL){
        return 0;
    }
    return j;
}

//删除
Status ListDelete(LinkList &head,int i,ElemType &e){
   LinkList p=head;
    int j=0;
   while ((p->next) && (j<i-1)){
       p=p->next;
       ++j;
    }

    if (!(p->next)||j>i-1){
        return ERROR;
    }
    LinkList q=p->next;
    e=q->data;
    p->next=q->next;
    delete q;
    return OK;
}

//头插法创建单链表
void CreateList_H(LinkList &head,int n){
    head=new LNode;
    head->next=NULL;
    for(int i=0;i<n;++i){
        LNode *p=new LNode;
        ElemType cin='a';
        cin>>p->data;
        p->next=head->next;
        head->next=p;
    }
}


//尾插法创建单链表
void CreateList_R(LinkList &head,int n){
    head=new LNode;
    head->next=NULL;
    LNode *r=head;
    for(int i=0;i<n;++i){
        LNode *p=new LNode;
        ElemType cin='a';
        cin>>p->data;
        p->next=NULL;
        r->next=p;
        r=p;
    }
}

int main()
{
    LinkList list;

    //初始化
    printf("单链表正在初始化....\n");
    int InitStatus=InitList(list);
    if (InitStatus=OK){
        printf("单链表初始化成功!\n");
    }else{
        printf("单链表初始化失败!\n");
    }

    choice();    //调用功能菜单函数
    int temp=1;  //通过改变temp的值来跳出while循环

    while(temp) {
        int flag;
        printf("请输入所需的功能编号:\n");
        scanf("%d",&flag);

        switch (flag) {//通过开关进行功能选择
            case 1:{//插入元素
                int insertIndex;
                ElemType inserElem;
                printf("请输入插入元素位置及插入元素(请在英文状态下输入): \n");
                scanf("%d,%c",&insertIndex,&inserElem);
                Status InsertS = ListInsert(list, insertIndex, inserElem);
                if(InsertS ==OK){
                    printf("向单链表%d个位置,插入元素为%c成功!\n",insertIndex,inserElem);
                    printf("======================================\n\n");
                }else{
                    printf("向单链表插入元素失败!\n");
                    printf("======================================\n\n");
                }
            }
                break;
            case 2:{//求单链表的长度
                int length=GetLinkListLength(list);
                printf("单链表的长度为:%d。 \n",length);
            }
                break;
            case 3:{//取值
                Status GetIndex;
                printf("请输入需要查询的元素的位置:\n");
                scanf("%d",&GetIndex);
                ElemType GetElem;
                int GetStatus=GetLinkList(list,GetIndex, GetElem);
                if (GetStatus=OK){
                    printf("从单链表中获取第%d位置元素成功,所获取到的元素为:%c。\n",GetIndex,GetElem);
                }else{
                    printf("从单链表中获取第%d位置元素失败!\n",GetIndex);
                }
            }
                break;
            case 4:{//查找
                //查找用引用型参数返回查找元素的位置
//                Status LocateIndex;
//                ElemType LocateElem;
//                printf("请输入想要查找元素:\n");
//                scanf("%c",&LocateElem);
//                LNode *LocateStatus = LocateLinkList(list,LocateElem,LocateIndex);
//                //printf("%d",LocateStatus);
//                if (LocateStatus == NULL) {
//                    printf("未查找到需要查找元素!\n");
//                } else {
//                    printf("查找到单链表中第%d元素为%c!\n",LocateIndex, LocateStatus->data);
//                }
                //查找用函数返回查找元素的位置
                ElemType LocateElem;
                printf("请输入想要查找元素:\n");
                getchar();    //用于接收回车
                scanf("%c",&LocateElem);
                Status LocateIndex = LocateLinkListElem(list,LocateElem);
                if (LocateIndex > 0) {
                    printf("从单链表中查找元素%c成功,它在单链表中的位置为第%d个!\n",LocateElem,LocateIndex);
                } else {
                    printf("从单链表中查找元素%c失败!\n",LocateElem);
                }
            }
                break;
            case 5:{//删除
                Status DeleteIndex;
                printf("请输入想要删除元素的位置:\n");
                scanf("%d",&DeleteIndex);
                ElemType DeleteElem;
                ElemType DeleteStatus = ListDelete(list,DeleteIndex,DeleteElem);
                if (DeleteStatus=OK){
                    printf("删除单链表第%d个位置的元素成功,删除的元素为:%c。\n",DeleteIndex,DeleteElem);
                }else{
                    printf("删除单链表第%d个位置的元素失败!\n",DeleteIndex);
                }
            }
                break;
            case 6:{//销毁
                Status DestoryStatus = DestoryLinkList(list);
                if (DestoryStatus == OK){
                    printf("单链表销毁成功!\n");
                }else{
                    printf("单链表销毁失败!\n");
                }
            }
                break;
            case 7:{//清空
                Status ClearStatus = ClearLinkList(list);
                if (ClearStatus == OK){
                    printf("单链表清空成功!\n");
                }else{
                    printf("单链表清空失败!\n");
                }
            }
                break;
            case 8:{//批量插入
                int on;
                printf("请输入想要插入的元素个数:\n");
                scanf("%d", &on);
                ElemType array[on];
                for (int i = 1; i <= on; i++) {
                    getchar();
                    printf("向单链表第%d个位置插入元素为:", (i));
                    scanf("%c", &array[i]);
                }

                for (int i = 1; i <= on; i++){
                    Status InsertStatus = ListInsert(list,i,array[i]);
                    if (InsertStatus=OK){
                        printf("向单链表第%d个位置插入元素%c成功!\n",i,array[i]);
                    }else{
                        printf("向单链表第%d个位置插入元素%c失败!\n",i,array[i]);
                    }
                }
            }
                break;
            case 9:{//退出程序
                temp=0;
//               return 0;
            }
                break;
            case 10:{//头插法创建单链表
//                ElemType EnterElement='e';
//                CreateList_H(list,EnterElement);
//                printf("前插法插入%c元素成功!\n",EnterElement);
            }
                break;
            case 11:{//尾插法创建单链表
//                ElemType EnterElem='a';
//                CreateList_R(list,EnterElem);
//                printf("后插法插入%c元素成功!\n",EnterElem);
            }
                break;
            default:
                printf("输入错误,无此功能,请检查输入:\n");
        }
    }

}

四、运行结果

 

 

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

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

相关文章

Centos使用Docker搭建自己的Gitlab(社区版和设置汉化、修改密码、设置SSH秘钥、添加拉取命令端口号)

根据我的经验 部署Gitlab&#xff08;社区版&#xff09; 至少需要2核4g的服务器 带宽3~4M 1. 在自己电脑上安装终端&#xff1a;宝塔ssl终端 或者 FinalShell&#xff0c;根据喜好安装即可 http://www.hostbuf.com/t/988.html http://www.hostbuf.com/downloads/finalshell_w…

xshell配置隧道转移规则

钢铁知识库&#xff0c;一个学习python爬虫、数据分析的知识库。人生苦短&#xff0c;快用python。 xshell是什么 通俗点说就是一款强大ssh远程软件&#xff0c;可以方便运维人员对服务器进行管理操作&#xff0c;功能很多朋友们自行探索&#xff0c;今天只聊其中一个功能点那…

中仕教育:研究生毕业可以考选调生吗?

选调生的报考条件之一是应届生&#xff0c;研究生毕业也属于应届生&#xff0c;所以是可以报考的。 选调生不同学历的年龄限制&#xff1a; 1.应届本科生&#xff1a;年龄在25岁以内 2.应届研究生&#xff1a;年龄在30岁以内 3.应届博士生&#xff1a;年龄在35岁以内 研究…

如何为不同品牌的笔记本电脑设置充电限制,这里提供详细步骤

笔记本电脑的电池健康状况至关重要。延长电池寿命可以帮你省下不少钱。对于长时间充电的Windows 11笔记本电脑用户来说,将电池电量限制在80%是很重要的。 虽然操作系统没有提供设置自定义电池充电限制的内置方法,但仍有一些方法可以在Windows 11中配置电池设置,并将其限制在…

kafka(一)——简介

简介 Kafka 是一种分布式、支持分区、多副本的消息中间件&#xff0c;支持发布-订阅模式&#xff0c;多用于实时处理大量数据缓存的场景&#xff0c;类似于一个“缓存池”。 架构 Producer&#xff1a;消息生产者&#xff1b;Consumer&#xff1a;消息消费者&#xff1b;Brok…

6. Spring Boot的starters

6. Spring Boot的starters(重要) 一般认为&#xff0c;SpringBoot 微框架从两个主要层面影响 Spring 社区的开发者们&#xff1a; 基于 Spring 框架的“约定优先于配置&#xff08;COC&#xff09;”理念以及最佳实践之路。提供了针对日常企业应用研发各种场景的 spring-boot…

人工智能原理实验2(2)——罗马尼亚问题(贪婪搜索、A*搜索、BFS、DFS)

&#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1; 根据上图以Zerind为初始状态&#xff0c;Bucharest为目标状态实现搜索&#xff0c;分别以贪婪搜索&#xff08;只考虑直线距离&#xff09;和A算法求解最短路径。 按顺序列出贪婪算法探索的扩展节点和其估价函数…

读书笔记-《数据结构与算法》-摘要8[桶排序]

桶排序和归并排序有那么点点类似&#xff0c;也使用了归并的思想。大致步骤如下&#xff1a; 设置一个定量的数组当作空桶。Divide - 从待排序数组中取出元素&#xff0c;将元素按照一定的规则塞进对应的桶子去。对每个非空桶进行排序&#xff0c;通常可在塞元素入桶时进行插入…

springboot113健身房管理系统

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的健身房管理系统 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取…

文件操作和IO(1)

认识文件 先来认识狭义上的文件(存储在硬盘(磁盘)上).针对硬盘这种持久化的I/O设备,当我们想要进行数据保存时,往往不是保存成一个整体,而是独立成一个个的单位进行保存,这个独立的单位就被抽象成文件的概念,就类似办公桌上的一份份真实的文件一般. 注意:硬盘 ! 磁盘 磁盘属于…

【算法与数据结构】1049、LeetCode 最后一块石头的重量 II

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题需要得到石头之间两两粉碎之后的最小值&#xff0c;那么一个简单的思路就是将这堆石头划分成大小相…

HDFS节点故障的容错方案

HDFS节点故障的容错方案 1. NN高可用1.1 选主逻辑1.2 HA切换1.3 注意点1.3.1 fencing的处理1.3.2 健康状态的定义1.3.3 确保zk中的父节点存在1.3.4 确保NN的ID与IP保持一致 2. DN高可用2.1 感知DN节点异常2.1.1 NN感知DN心跳超时2.1.1 客户端链接DN异常 2.2 异常DN上的数据处理…

6.4.4释放音频

6.4.4释放音频 许多Flash动画里的音乐或歌曲非常好听&#xff0c;能不能在没有源文件的情况下把里面的声音文件取出来呢&#xff1f;利用Swf2VideoConverter2可以轻松做到这一点。 1&#xff0e;单击“添加”按钮&#xff0c;在弹出的下拉菜单中选择“添加文件”&#xff0c;…

蓝桥备战--分糖果OJ2928 贪心 分类讨论

题目&#xff1a; 思路&#xff1a; 首先排序(经验之谈) 分类讨论 我们要做到不重不漏的分类 代码&#xff1a; #include <iostream> #include <algorithm> using namespace std;const int N 1e6 10;char dist[N]; int n, x;int main() {string str;cin >…

以超市数据微案例-fineBI可视化分析

一、入门案例&#xff1a; 2.分析思路&#xff1a; 数据清晰界面中添加毛利额计算 **所以在新增步骤之后&#xff0c;必须点击保存并更新&#xff0c;否则可视化界面中无法使用最新的数据 4、数据可视化分析 1&#xff09;销售额最高的十大商品种类 为1-8月超市数据&#xff…

测试用例评审流程

1:评审的过程 A:开始前做好如下准备 1、确定需要评审的原因 2、确定进行评审的时机 3、确定参与评审人员 4、明确评审的内容 5、确定评审结束标准 6、提前至少一天将需要评审的内容以邮件的形式发送给评审会议相关人员。并注明详审时间、地点及偿参与人员等。 7、 在邮件中提醒…

每日一题——1295.统计位数为偶数的数字

方法一 个人方法&#xff1a; 想知道整数型数字有多少位&#xff0c;可以直接把数字转字符&#xff0c;看字符的长度就是数字的位数 var findNumbers function(nums) {let count0for(let num of nums){let strnumif(str.length%20) count}return count }; 消耗时间和内存情况…

【LLM-agent】function call功能、AgentTuning微调

note function call本质&#xff1a;准确识别用户的语义&#xff0c;将其转为结构化的指令&#xff0c;其中通过LLM理解指令和上下文判断需要调用哪个函数、抽取出input中函数所需的参数。是用户和界面交互方式产生质变的一个trick。所以为了提高模型准确识别和调用函数的能力…

HTML+JavaScript-01

说明 之前有一篇JavaWeb-JavaScript中只是简单介绍了一点JavaScript的内容&#xff0c;这篇笔记算是续写的&#xff0c;但是从01开始编号。 引入js文件 html、css、js俗称前端三剑客&#xff0c;一般都是分开写&#xff0c;先写框架、再写css、最后写js。因此在工程量大的情…

第36集《佛法修学概要》

请大家打开讲义第九十六面&#xff0c;我们讲到禅定的修学方便。 在我们发了菩提心&#xff0c;安住菩萨种性以后&#xff0c;我们开始操作六度的法门。六度的法门&#xff0c;它有两个不同的差别的内容&#xff0c;一种是成就我们的善业力&#xff0c;另外一种&#xff0c;是…