C语言 实现链表的各种功能

C语言实现链表的各种功能

链表的定义

链表是一种数据结构,它是由一系列节点组成的线性结构。每个节点包含两个部分:数据和指针。数据部分存储着实际的数据,指针部分指向下一个节点。

链表的特点是:

  • 每个节点都可以自由地插入或删除。
  • 链表的第一个节点称为头节点,最后一个节点称为尾节点。
  • 链表中节点的数量可以动态变化。

链表的实现

链表的实现可以分为两步:

  1. 定义链表节点的结构。
  2. 实现链表的操作函数。

定义链表节点的结构

文件名:link_list.h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

typedef int ElemType;

typedef struct linkList{
    ElemType data;
    struct linkList* next;
}LNode;

//初始化链表
bool initList(LNode** head);

//链表是否为空
bool isEmpty(LNode* head);

//链表长度
int length(LNode* head);

//链表头部插入元素
bool insert(LNode* head, ElemType data);

//链表尾部插入元素
bool append(LNode* head, ElemType data);

//插入链表指定位置
bool insertAt(LNode* head, ElemType data, int pos);

//链表删除元素头删
bool delete(LNode* head);

//链表删除指定位置元素
bool deleteAt(LNode* head, int pos);

//删除链表元素尾删
bool deleteTail(LNode* head);


//链表中查找指定位置元素
LNode* searchAt(LNode* head, int pos);

//修改链表指定位置元素
bool modify(LNode* head, ElemType data, int pos);

//清空链表
bool clearList(LNode* head);

//销毁链表
bool destroyList(LNode** head);

//打印链表
bool printList(LNode* head);

实现链表的操作函数

文件名:link_list.c


#include "link_list.h"

#define DEBUG_PRINT 1

//初始化链表
bool initList(LNode** head){
    if(NULL==head){
#if DEBUG_PRINT
        printf("初始化链表的入参为空\n");
#endif
        return false;
    }
    //初始化  calloc()申请的空间自动初始化为0
    (*head)=(LNode*)calloc(1, sizeof(LNode));
    (*head)->next=NULL;
    (*head)->data=0;//头节点中数据用来保存链表中的元素个数
    return true;
}
//链表是否为空
bool isEmpty(LNode* head){
    if(NULL==head){
#if DEBUG_PRINT
        printf("isEmpty()的入参为空\n");
#endif
        return false;
    }
    if(head->next==NULL){
        return true;
    }
    return false;
}
//链表长度
int length(LNode* head){
    if(NULL==head){
#if DEBUG_PRINT
        printf("length()的入参为空\n");
#endif
        return false;
    }
    return head->data;
}
//链表头部插入元素
bool insert(LNode* head, ElemType data){
    //入参判断
    if(NULL==head){
#if DEBUG_PRINT
        printf("insert()的入参为空\n");
#endif
        return false;
    }

    //为新节点申请空间
    LNode * newNode=(LNode*)calloc(1, sizeof(LNode));
    newNode->data=data;
    newNode->next=head->next;
    head->next=newNode;
    head->data++;
}
//链表尾部插入元素
bool append(LNode* head, ElemType data){
    //入参判断
    if(NULL==head){
#if DEBUG_PRINT
        printf("insert()的入参为空\n");
#endif
        return false;
    }
    //为新节点申请空间
    LNode * newNode=(LNode*)calloc(1, sizeof(LNode));
    newNode->data=data;

   // LNode *temp=head->next;//head->next可能为NULL,下方对temp->next=(NULL->next),会报错
    LNode *temp=head;
    while (temp->next!=NULL){
        temp=temp->next;
    }
    newNode->next=temp->next;
    temp->next=newNode;
    head->data++;
    return true;
}
//插入链表指定位置
bool insertAt(LNode* head, ElemType data, int pos){
    //入参判断
    if(NULL==head){
#if DEBUG_PRINT
        printf("insertAt()的入参为空\n");
#endif
        return false;
    }
    if(pos<0|| pos>head->data ){
#if DEBUG_PRINT
        printf("insertAt()的插入位置不合理\n");
#endif
        return false;
    }
    LNode *temp=head;
    int  flg=0;//标记循环的次数是否到了插入位置 ,没到说明插入位置不合理
    for (int i = 0; i < pos; ++i) {
        flg++;
        if(temp->next!=NULL){
            temp=temp->next;
        } else{
            break;
        }
    }
    if(flg==pos){
        //为新节点申请空间
        LNode * newNode=(LNode*)calloc(1, sizeof(LNode));
        newNode->data=data;
        newNode->next= temp->next;
        temp->next=newNode;
        head->data++;
        return true;
    } else{
        return false;
    }
}
//链表删除元素头删
bool delete(LNode* head){
    //入参判断
    if(NULL==head){
#if DEBUG_PRINT
        printf("delete()的入参为空\n");
#endif
        return false;
    }
    if(isEmpty(head)){
        printf("链表已空\n");
        return true;
    }
    LNode *temp=head->next;
    head->next=head->next->next;
    free(temp);
    head->data--;
    return true;

}
//链表删除指定位置元素
bool deleteAt(LNode* head, int pos){
    //入参判断
    if(NULL==head ){
#if DEBUG_PRINT
        printf("deleteAt()的入参为空\n");
#endif
        return false;
    }
    if(NULL==head->next){ //要判断NULL==head->next 下面temp=head->next
        printf("空表不能删除\n");
        return false;
    }
    if(pos<0|| pos >= head->data ){
#if DEBUG_PRINT
        printf("deleteAt()的删除位置不合理\n");
#endif
        return false;
    }
    LNode *temp=head->next; //temp=head->next保证删除0位置也正常返回
    LNode *P=head;
    int flg=0;
    for (int i = 0; i < pos; ++i) {
        flg++;
        if(temp->next!=NULL){ //保证temp->next不能指空
            P=temp;
            temp=temp->next;
        } else{
            break;
        }
    }
    if(flg==pos){//查0位置不走循环,返回了temp=head->next
        P->next=temp->next;
        free(temp);
        head->data--;
        return true;
    } else{
        return false;
    }

}
//删除链表元素尾删
bool deleteTail(LNode* head){
    //入参判断
    if(NULL==head ){
#if DEBUG_PRINT
        printf("delete()的入参为空\n");
#endif
        return false;
    }
    //只有头节点无需删除
    if(NULL==head->next){
        printf("表只有头节点\n");
        return true;
    }

    //找到尾节点的前一个节点
    LNode *temp=head;
    LNode * P=NULL;
    while (temp->next!=NULL){
        P=temp;
        temp=temp->next;
    }
    if(P){
        //循环退出时P指向尾节点的前一个节点,temp就是尾节点
        P->next=NULL;
        free(temp);
        head->data--;
    }

    return true;
}
//链表中查找指定位置元素
LNode* searchAt(LNode* head, int pos){
    //入参判断
    if(NULL==head ){
#if DEBUG_PRINT
        printf("insertAt()的入参为空\n");
#endif
        return false;
    }
    if(NULL==head->next){ //要判断NULL==head->next 下面temp=head->next
        printf("空表不能查询\n");
        return false;
    }
    if(pos<0|| pos >= head->data ){
#if DEBUG_PRINT
        printf("searchAt()的查找位置不合理\n");
#endif
        return false;
    }

    LNode *temp=head->next; //temp=head->next保证查0位置也正常返回
    int flg=0;
    for (int i = 0; i < pos; ++i) {
        flg++;
        if(temp!=NULL){
            temp=temp->next;
        } else{
            break;
        }
    }
    if(flg==pos){//查0位置不走循环,返回了temp=head->next
        return temp;
    } else{
        return false;
    }


}
//修改链表指定位置元素
bool modify(LNode* head, ElemType data, int pos){
    //入参判断
    if(NULL==head ){
#if DEBUG_PRINT
        printf("modify()的入参为空\n");
#endif
        return false;
    }
    if(NULL==head->next){ //要判断NULL==head->next 下面temp=head->next
        printf("空表不能查询\n");
        return false;
    }
    if(pos<0|| pos >= head->data ){
#if DEBUG_PRINT
        printf("modify()的修改位置不合理\n");
#endif
        return false;
    }

    LNode *temp=head->next; //temp=head->next保证修改0位置也正常返回
    int flg=0;
    for (int i = 0; i < pos; ++i) {
        flg++;
        if(temp!=NULL){
            temp=temp->next;
        } else{
            break;
        }
    }
    if(flg==pos){
        temp->data=data;
        return true;
    } else{
        return false;
    }
}
//清空链表
bool clearList(LNode* head){
    //入参判断
    if(NULL==head ){
#if DEBUG_PRINT
        printf("clearList()的入参为空\n");
#endif
        return false;
    }
    if(NULL==head->next){ //要判断NULL==head->next 下面temp=head->next
        printf("链表中没有数据\n");
        return true;
    }
    LNode * temp=head->next;
    LNode *P=head;
    while (temp!=NULL){
        P=temp;
        temp=temp->next;
        free(P);
        head->data--;
    }
    head->next=NULL;
    return true;

}

//销毁链表
bool destroyList(LNode** head){
    //入参判断
    if(NULL==head || NULL==*head){
#if DEBUG_PRINT
        printf("destroyList()的入参为空\n");
#endif
        return false;
    }
    clearList(*head);
    free(*head);
    (*head)=NULL;
    return true;
}

//打印链表
bool printList(LNode* head){
    //入参检查
    if(NULL==head){
#if DEBUG_PRINT
        printf("length()的入参为空\n");
#endif
        return false;
    }
    if(NULL==head->next){
        printf("表为空\n");
        return true;
    }
    LNode *temp=head->next;
    while (temp){
        printf("%d ",temp->data);
        temp=temp->next;
    }
    printf("\n");
    return true;
}



main.c测试功能

文件名:main.c
#include "link_list.h"

int main(){
    LNode *head;
    initList(&head);
    printf("head=%p\n",head);
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));
    printf("----------------------------\n");

    //测试头插
    insert(head,100);
    insert(head,200);
    insert(head,300);
    printList(head);
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));
    //300 200 100
    printf("----------------------------\n");
    //测试尾插
    append(head,400);
    append(head,500);
    append(head,600);
    printList(head);
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));
    //300 200 100 400 500 600
    printf("----------------------------\n");
    //测试插入链表指定位置
    insertAt(head,333,1);
    insertAt(head,444,0);
    insertAt(head,555,8);//最后一个插入
    insertAt(head,666,10);//报错///insertAt()的插入位置不合理
    printList(head);//444 300 333 200 100 400 500 600 555
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));
    printf("----------------------------\n");
    //链表删除元素头删
    delete(head);
    delete(head);
    printList(head);//333 200 100 400 500 600 555
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));
    printf("----------------------------\n");
    //删除链表元素尾删
    deleteTail(head);
    printList(head);//333 200 100 400 500 600
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));//length=6
    printf("----------------------------\n");
    //链表中查找指定位置元素
    LNode *N=NULL;
    searchAt(head,-1);//位置不合理
    N=searchAt(head,6);//位置不合理
    N=searchAt(head,5);//查找数据:600
    if(N){
        printf("查找数据:%d\n",N->data);
    } else{
        printf("没查到\n");
    }
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));
    printf("----------------------------\n");
    //修改链表指定位置元素
    modify(head,777,0);
    modify(head,888,6);//modify()的修改位置不合理
    printList(head);//777 200 100 400 500 600
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));
    printf("----------------------------\n");
    //链表删除指定位置元素
    deleteAt(head,0);
    printList(head);//200 100 400 500 600
    printf("Empty=%d\n",isEmpty(head));
    printf("length=%d\n",length(head));
    printf("----------------------------\n");
    //清空链表
    clearList(head);
    printf("head=%p\n",head);//head=0000000000B11450
    printf("head->next=%p\n",head->next);//head->next=0000000000000000
    printList(head);//表为空
    printf("Empty=%d\n",isEmpty(head));//Empty=1
    printf("length=%d\n",length(head));//length=0
    printf("----------------------------\n");

    //销毁
    destroyList(&head);
    printf("head=%p\n",head);//head=0000000000000000
    printf("----------------------------\n");
}

总结

链表是一种常见的数据结构,在实际应用中有着广泛的应用。本文介绍了链表的定义、实现、操作、测试等功能。

链表的实现主要是定义链表节点的结构,然后实现链表的操作函数。链表的操作函数包括:初始化链表、链表是否为空、链表长度、链表头部插入元素、链表尾部插入元素、插入链表指定位置、链表删除元素头删、链表删除指定位置元素、删除链表元素尾删、链表中查找指定位置元素、修改链表指定位置元素、清空链表、销毁链表、打印链表。

链表的操作函数都有相应的注释,可以很方便地理解各个函数的作用。

链表的测试代码主要是对链表的操作函数进行测试 ,可以作为学习链表的入门代码。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决obsidian加粗字体显示不突出的问题

加粗字体显示不突出的原因&#xff1a;默认字体的加粗版本本来就不突出 解决方法&#xff1a;改成显示突出的类型Microsoft YaHei UI 【效果】 修改前&#xff1a;修改后&#xff1a; 其他方法&#xff1a; 修改css&#xff08;很麻烦&#xff0c;改半天也不一定奏效&#…

mac上使用finder时候,显示隐藏的文件或者文件夹

默认在finder中是不显示隐藏的文件和文件夹的&#xff0c;但是想创建.gitignore文件&#xff0c;并向里面写入内容&#xff0c;即便是打开xcode也是不显示这几个隐藏文件的&#xff0c;那有什么办法呢&#xff1f; 使用快捷键&#xff1a; 使用finder打开包含隐藏文件的文件夹…

CleanMyMac残留项可以删除吗 mac清理卸载残留文件怎么清理 如何清除MacBook上残留的软件垃圾

如果您不知道Mac电脑如何删除文件&#xff0c;不知道如何删除残留文件&#xff0c;不用担心&#xff0c;本篇文章为大家介绍删除普通文件和删除应用卸载后残留文件的方法。 苹果电脑怎么删除文件&#xff1f; 对于一般的文件&#xff0c;在Mac上将其删除掉不是一件很难的事&a…

【Python】字典练习

python期考练习 目录 1. 首都名​编辑 2. 摩斯电码 3. 登录 4. 学生的姓名和年龄​编辑 5. 电商 6. 学生基本信息 7. 字母数 1. 首都名 初始字典 (可复制) : d{"China":"Beijing","America":"Washington","Norway":…

信息学奥赛初赛天天练-42-CSP-J2020基础题-变量地址、编译器、逻辑运算、逻辑与运算、逻辑或运算、冒泡排序、递归应用

PDF文档公众号回复关键字:20240702 2020 CSP-J 选择题 单项选择题&#xff08;共15题&#xff0c;每题2分&#xff0c;共计30分&#xff1a;每题有且仅有一个正确选项&#xff09; 1.在内存储器中每个存储单元都被赋予一个唯一的序号&#xff0c;称为&#xff08; &#xff0…

pandas数据分析(4)

修改DataFrame数据的最简单的方法是通过loc和iloc属性为某些元素赋值。 首先构造一组数据 通过标签或位置设置值 也可以一次修改多个值&#xff1a; 通过布尔索引设置数据 将所有来自China&#xff0c;或者年龄20以下的人名字设置为匿名&#xff1a; 通过替换值设置数据 如果…

粤港联动,北斗高质量国际化发展的重要机遇

今年是香港回归27周年&#xff0c;也是《粤港澳大湾区发展规划纲要》公布5周年&#xff0c;5年来各项政策、平台不断为粤港联动增添新动能。“十四五”时期的粤港澳大湾区&#xff0c;被国家赋予了更重大的使命&#xff0c;国家“十四五”《规划纲要》提出&#xff0c;以京津冀…

EEPROM内部原理

A2, A1, A0是EEPROM的地址引脚&#xff0c;用于设置设备地址。它们的作用如下&#xff1a; 设备寻址&#xff1a; 这三个引脚允许在I2C总线上唯一地标识EEPROM芯片。通过不同的连接方式&#xff08;接高、接低或悬空&#xff09;&#xff0c;可以为同一类型的EEPROM芯片设置不同…

[PyTorch]:加速Pytorch 模型训练的几种方法(几行代码),最快提升八倍(附实验记录)

本篇文章转自&#xff1a;Some Techniques To Make Your PyTorch Models Train (Much) Faster 本篇博文概述了在不影响 PyTorch 模型准确性的情况下提高其训练性能的技术。为此&#xff0c;将 PyTorch 模型包装在 LightningModule 中&#xff0c;并使用 Trainer 类来实现各种训…

Ubuntu开通5005端口 记录

Ubuntu版本&#xff1a;20.04 使用systemctl status firewalld查看防火墙状态&#xff0c;报错Unit firewalld.service could not be found 报错的原因是没有安装firewall&#xff0c;安装命令为sudo apt install firewalld&#xff0c;然后进行安装 安装完成后输入systemctl…

【日常记录】【JS】动态执行JS脚本

文章目录 1、第一种方式&#xff1a;eval2、第二种方式&#xff1a;setTimeout3、第三种方式&#xff1a;创建script 标签插入body4、第四种方式&#xff1a;创建 Function5、对比6、 参考链接 1、第一种方式&#xff1a;eval 语法 eval(string)参数 string&#xff1a;一个…

Windows编程上

Windows编程[上] 一、Windows API1.控制台大小设置1.1 GetStdHandle1.2 SetConsoleWindowInfo1.3 SetConsoleScreenBufferSize1.4 SetConsoleTitle1.5 封装为Innks 2.控制台字体设置以及光标调整2.1 GetConsoleCursorInfo2.2 SetConsoleCursorPosition2.3 GetCurrentConsoleFon…

DLS-42/5-5双位置继电器 DC220V 板后接线 约瑟JOSEF

DLS-40系列双位置继电器型号&#xff1a; DLS-41/10-2双位置继电器&#xff1b; DLS-41/9-3双位置继电器 DLS-41/8-4双位置继电器&#xff1b; DLS-41/6-6双位置继电器&#xff1b; DLS-42/9-1双位置继电器&#xff1b; DLS-42/8-2双位置继电器&#xff1b; DLS-42/7-3双位…

2024护网整体工作预案示例

目录 第1章 HW整体工作工作部署 1.1 工作组织架构 1.2 各部门工作职责 1.3 演练期间工作机制 1.3.1 工作汇报机制 1.3.2 应急响应机制 第2章 系统资产梳理整改 2.1 敏感信息梳理整改 2.2 互联网资产发现 2.3 第三方供应商梳理 2.4 业务连接单位梳理 第3…

【C++】main函数及返回值深度解析

一.main函数介绍 1.main函数怎么写 #include <iostream>int main() {// 程序的代码放在这里std::cout << "Hello, World!" << std::endl;return 0; }在这个例子中&#xff1a; #include <iostream> 是预处理指令&#xff0c;它告诉编译器…

入门Axure:快速掌握原型设计技能

2002 年&#xff0c;维克托和马丁在旧金山湾区的一家初创公司工作&#xff0c;发现自己一再被软件开发生命周期的限制所困扰&#xff0c;而且产品团队在编写规范之前很难评估他们的解决方案&#xff0c;开发人员经常不理解&#xff08;或不阅读&#xff09;给出的规范&#xff…

02.C1W1.Sentiment Analysis with Logistic Regression

目录 Supervised ML and Sentiment AnalysisSupervised ML (training)Sentiment analysis Vocabulary and Feature ExtractionVocabularyFeature extractionSparse representations and some of their issues Negative and Positive FrequenciesFeature extraction with freque…

前端人注意了!Nuxt 的服务器专用组件应该引起你的关注!!

大家好&#xff0c;我是CodeQi&#xff01; 前几天&#xff0c;我和同事们在讨论 Nuxt.js 的一些新特性时&#xff0c;突然发现一件有趣的事情&#xff1a;Nuxt 的服务器专用组件&#xff08;Server-only Components&#xff09;引起了大家的极大兴趣。 为了不显得太落伍&am…

【unity实战】使用旧输入系统Input Manager 写一个 2D 平台游戏玩家控制器——包括移动、跳跃、滑墙、蹬墙跳

最终效果 文章目录 最终效果素材下载人物环境 简单绘制环境角色移动跳跃视差和摄像机跟随效果奔跑动画切换跳跃动画&#xff0c;跳跃次数限制角色添加2d物理材质&#xff0c;防止角色粘在墙上如果角色移动时背景出现黑线条方法一方法二 墙壁滑行实现角色滑墙不可以通过移动离开…

MySQL——事务ACID原则、脏读、不可重复读、幻读

什么是事务 要么都成功&#xff0c;要么都失败 一一一一一一一 1. SQL执行&#xff1a;A给B转账 A 1000 ---->200 B 200 2. SQL执行&#xff1a;B收到A的钱 A 800 B 400 一一一一一一一 将一组SQL放在一个批次中去执行~ 事务原则&#xff1a;ACI…