c语言链表实现

(注意事项都已经在代码中标注)

1.链表相关函数的头文件

#define  _CRT_SECURE_NO_WARNINGS
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
typedef int datatype;
typedef struct slistnode {
    datatype data;
    struct slistnode* node;
}slnode;
void menu();
void slprint(slnode* slist1);//展示
void slpush_back(slnode** slist1, datatype x);//尾增
void slpush_front(slnode** slist1, datatype x);//头增
slnode* sl_find(slnode* slist1, datatype x);//查找

void slpop_back(slnode** slist1);//尾删
void slpop_front(slnode** slist1);//头删
void slpush_onin(slnode** slist1, slnode* pos, datatype x);//在指定位置前面增,这里使用的是找前驱,但是实际上可以改该位置的数据,再生成一个新的结点使用该位置的data连接上去,就不需要找前驱
void slpop_onin(slnode** slist1, slnode* pos);//删除指定位置的数据




2.具体实现的函数

#include "slist.h"
void menu() {
    printf("******************************\n");
    printf("***1.头插            2.尾插***\n");
    printf("***3.头删            4.尾删***\n");
    printf("***5.在指定数前面增加一个数***\n");
    printf("***6.删除指定第一个数      ***\n");
    printf("***0.exit                  ***\n");
    printf("******************************\n");

}
void slprint(slnode* slist1) {
    
    if (slist1 == NULL) {
        printf("该链表暂时并没有任何的结点,无法打印\n");
    }
    else{
        printf("开始打印该链表中的内容:");
        while (slist1 != NULL) {
            
            printf("%d->", slist1->data);
            slist1 = slist1->node;
        }
        printf("NULL");
        printf("\n打印结束\n");
        printf("-----------------------------\n");
    }

}
slnode* buynewnode(datatype x) {
    slnode* newnode = (slnode*)malloc(sizeof(slnode));
    if (newnode != NULL) {
        newnode->data = x;
        newnode->node = NULL;
        return newnode;
    }
    else {
        printf("buynewnode err:%s\n", strerror(errno));
        return NULL;
    }
}
void slpush_back(slnode** slist1, datatype x) {
    slnode* newnode = buynewnode(x);
    if (*slist1 == NULL) {
        *slist1 = newnode;//这里就是尾删为什么使用二级指针的原因
    }
    else {
        slnode* slist_tmp = *slist1;
        while (slist_tmp->node != NULL) {
            slist_tmp = slist_tmp->node;
        }
        slist_tmp->node =newnode;
    }
}
void slpush_front(slnode** slist1, datatype x) {
    slnode* newnode = buynewnode(x);
    if (*slist1 == NULL) {
        *slist1 = newnode;//这里就是头插为什么使用二级指针的原因
    }
    else {
        newnode->node = *slist1;
        *slist1 = newnode;
    }
}
slnode* sl_find(slnode* slist1, datatype x) {
    if (slist1 == NULL) {
        printf("该链表暂时为空\n");
        return NULL;
    }
    else{
        while (slist1->data != x) {
            slist1 = slist1->node;
        }
        return slist1;
    
    }
    
}
void slpop_back(slnode** slist1) {
    slnode* prev = *slist1;
    slnode* slist1_tmp = *slist1;
    if (slist1_tmp == NULL) {
        return;
    }
    else if(slist1_tmp->node==NULL){
        free(*slist1);
        *slist1 = NULL;//这里的分类讨论要注意,为什么在尾删也需要二级指针,因为在这里需要直接让他指向空;头指针发生了变化
    }
    else {
        while (slist1_tmp->node != NULL) {
            prev = slist1_tmp;
            slist1_tmp = slist1_tmp->node;

        }
        prev->node = NULL;
        free(slist1_tmp);//这里没有分类讨论的话,前驱跟找尾部的指针会指向同一个,会有特殊的地方

    }
}
void slpop_front(slnode** slist1) {
    slnode* flag_slist1 = *slist1;
    if (*slist1 == NULL) {
        return;
    }
    else {
        (*slist1) = (*slist1)->node;//头删很显然就是需要使用二级指针的
        free(flag_slist1);
        flag_slist1 = NULL;
    }

}
void slpush_onin(slnode** slist1, slnode *pos,datatype x) {//找到的该数后在前面增加一个数
    if (*slist1==pos) {
        slpush_front(slist1, x);
    }
    else{
        slnode* slist1_tmp = *slist1;
        while (slist1_tmp->node != pos) {
            slist1_tmp = slist1_tmp->node;
        }
        slnode* newnode = buynewnode(x);
        slist1_tmp->node = newnode;
        newnode->node = pos;
    }
}
void slpop_onin(slnode** slist1, slnode* pos) {//删除指定位置的的数,上下这两个都是在一个的时候会有特殊情况,就是相当于头删和头增
    if (*slist1 == pos) {
        slpop_front(slist1);
    }
    else {
        slnode* slist1_tmp = *slist1;
        while (slist1_tmp->node != pos) {
            slist1_tmp = slist1_tmp->node;
        }
        slist1_tmp->node = pos->node;
        free(pos);
        
    }
}




3.主函数

#include "slist.h"
int main() {
    int input = 0;
    slnode* slist1 = NULL;
    do {
        menu();
        printf("请输入你想要进行的操作数\n");
        scanf("%d", &input);
        switch (input) {
        case 1:
            printf("请输入你要头插的数\n");
            int n = 0;
            scanf("%d", &n);
            slpush_front(&slist1, n);
            slprint(slist1);
            break;
        case 2:
            printf("请输入你要尾插的数\n");
            n = 0;
            scanf("%d", &n);
            slpush_back(&slist1, n);
            slprint(slist1);
            break;
        case 3:
            printf("正在进行头删\n");
            slpop_front(&slist1);
            slprint(slist1);
            printf("头删结束\n");
            break;
        case 4:
            printf("正在进行尾删\n");
            slpop_back(&slist1);
            slprint(slist1);
            printf("尾删结束\n");
            break;
        case 5:
            printf("正在进行指定数前加\n");
            printf("请输入指定数\n");
            int x = 0;
            scanf("%d", &x);
            slnode* pos = sl_find(slist1,x);
            if (pos) {
                printf("可以进行前加,正在进行前加\n");
                printf("请输入你要加入的数\n");
                scanf("%d", &n);
                slpush_onin(&slist1, pos, n);

            }
            else
                printf("没有找到指定的数\n");
            slprint(slist1);
            break;
        
        case 6:
            printf("正在进行指定数删除\n");
            printf("请输入指定数\n");
            x = 0;
            scanf("%d", &x);
            pos = sl_find(slist1, x);
            if (pos) {
                printf("正在进行删除\n");
                
                
                slpop_onin(&slist1, pos);

            }
            else
                printf("没有找到指定的数\n");
            slprint(slist1);
            break;
        case 0:
            printf("正在退出程序\n");
            break;
        default:
            printf("您的输入存在错误\n");
        }
    
    } while (input);
    
    return 0;

}
//注意事项,当在指定位置进行插入的时候,只有一个相当于头插,不能直接使用原来的方法,否则会报错
//同理删指定位置,就相当于头删

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

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

相关文章

vscode写markdown插入图片视频并放在指定目录

目录 前言正文 前言 各种云文档非常好用&#xff0c;但是当你想把这些资料保存在本地时&#xff0c;markdown我觉得是最好的选择 markdown编辑器也有很多&#xff0c;但我还是觉得vscode最好用&#xff0c;直接粘贴文件就可以插入也类似云文档的使用体验&#xff0c;但是想要…

外卖点餐系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;外卖员管理&#xff0c;餐厅管理&#xff0c;用户管理&#xff0c;菜品分类管理&#xff0c;菜品信息管理&#xff0c;外卖订单管理&#xff0c;订单配送管理 微信端账号功能包括&#xff1a;系统首页…

OKHTTP 如何处理请求超时和重连机制

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

Linux下Docker方式Jenkins安装和配置

一、下载&安装 Jenkins官方Docker仓库地址&#xff1a;https://hub.docker.com/r/jenkins/jenkins 从官网上可以看到&#xff0c;当前最新的稳定版本是 jenkins/jenkins:lts-jdk17。建议下在新的&#xff0c;后面依赖下不来 所以&#xff0c;我们这里&#xff0c;执行doc…

VS+QT 自定义插件变成动态库加载及使用

一、前言 有个界面需要重复使用某个自定义的控件&#xff0c;希望自定义控件能够像动态库文件那样&#xff0c;添加引用lib就能使用&#xff0c;经过多次太坑后&#xff0c;总结如下 二、实现方式 ① 新建项目&#xff0c;选择"Qt Designer Custom Widget" 创建自定…

Kubernetes(k8s) 与 docker 间 镜像导入

docker 导出&#xff0c;k8s 导入 docker 镜像导出 查看镜像 docker images结果 REPOSITORY TAG IMAGE ID CREATED SIZE openjdk jz23 092ed76962fb 3 hours ago 694MB导出镜…

python爬虫 - 进阶正则表达式

&#x1f308;个人主页&#xff1a;https://blog.csdn.net/2401_86688088?typeblog &#x1f525; 系列专栏&#xff1a;https://blog.csdn.net/2401_86688088/category_12797772.html 目录 前言 一、匹配中文 &#xff08;一&#xff09;匹配单个中文字符 &#xff08;二…

JavaEE-进程与线程

1.进程 1.1什么是进程 每个应⽤程序运⾏于现代操作系统之上时&#xff0c;操作系统会提供⼀种抽象&#xff0c;好像系统上只有这个程序在运 ⾏&#xff0c;所有的硬件资源都被这个程序在使⽤。这种假象是通过抽象了⼀个进程的概念来完成的&#xff0c;进程可 以说是计算机科学…

【动态规划】子数组系列(上)

1. 最大子数组和 53. 最大子数组和 状态表示&#xff1a;以 i 位置为结尾时的所有子数组中的最大和 状态转移方程&#xff1a; i 位置为结尾的子数组又可以分为长度为 1 的和大于 1 的&#xff0c;长度为 1 就是 nums[i] &#xff0c;长度不为 1 就是 dp[i - 1] nums[i]&…

Javascript笔试题目(三)

1.如何使用JS实现setTimeout功能来模拟setlnterva请写出具体代码 在JavaScript中&#xff0c;setTimeout 和 setInterval 是两个常用的定时器函数&#xff0c;但它们的行为有所不同。setTimeout 用于在指定的延迟后执行一次代码&#xff0c;而 setInterval 则用于每隔指定的时…

Ubuntu中vscode如何选择ROS版本

Ubuntu中可能安装了多个ROS版本&#xff0c;比如ROS1 noetic&#xff0c; ROS2 foxy, humble等。有时候需要在vscode中对ROS程序进行debug&#xff0c;一般会先安装ROS插件。当电脑上有多个ROS版本时&#xff0c;选择Debug中选择ROS&#xff1a;Launch ROS:Attach(ROS1)或者ROS…

Prometheus + Grafana 监控 MySQL 数据库

文章目录 1、前置介绍2、搭建流程2.1、安装 Docker2.2、安装 MySQL2.3、安装 MySQL Exporter2.4、安装 Prometheus2.5、安装 Grafana 1、前置介绍 本次监控平台搭建&#xff0c;我使用2台阿里云服务器来完成本次的搭建部署操作&#xff0c;配置如下&#xff1a; 阿里云ECS1&am…

【宝可梦】游戏

pokemmo https://pokemmo.com/zh/ 写在最后&#xff1a;若本文章对您有帮助&#xff0c;请点个赞啦 ٩(๑•̀ω•́๑)۶

Word文档功能快捷键大全

以下是 Microsoft Word 的全面快捷键大全&#xff0c;涵盖了文档操作、文本编辑、格式化、导航等多种功能&#xff0c;帮助你提高工作效率。 Word 全面快捷键和快捷方式表 功能类别快捷键/快捷方式功能描述基本文档操作Ctrl N新建文档Ctrl O打开文档Ctrl S保存文档F12另存…

AI金融攻防赛:金融场景凭证篡改检测(DataWhale组队学习)

引言 大家好&#xff0c;我是GISer Liu&#x1f601;&#xff0c;一名热爱AI技术的GIS开发者。本系列文章是我跟随DataWhale 2024年10月学习赛的AI金融攻防赛学习总结文档。本文主要讲解如何解决 金融场景凭证篡改检测的核心问题&#xff0c;以及解决思路和代码实现过程。希望…

48 Redis

48 Redis 前言 Redis&#xff08;Remote Dictionary Server )&#xff0c;即远程字典服务。是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库&#xff0c;并提供多种语言的API。 redis会周期性的把更新的数据写入磁盘或者把修改操…

[C++][第三方库][RabbitMq]详细讲解

目录 1.介绍2.安装1.RabbitMq2.客户端库 3.AMQP-CPP 简单使用1.介绍2.使用 4.类与接口1.Channel2.ev 5.使用1.publish.cc2.consume.cc3.makefile 1.介绍 RabbitMQ&#xff1a;消息队列组件&#xff0c;实现两个客户端主机之间消息传输的功能(发布&订阅)核心概念&#xff1…

网络受限情况下安装openpyxl模块提示缺少Jdcal,et_xmlfile

1.工作需要处理关于Excel文件内容的东西 2.用公司提供的openpyxl模块总是提示缺少jdcal文件,因为网络管控,又没办法直接使用命令下载&#xff0c;所以网上找了资源&#xff0c;下载好后上传到个人资源里了 资源路径 openpyxl jdcal et_xmlfile 以上模块来源于&#xff1a;Py…

Python读取pdf中的文字与表格

一、PyPDF2包安装 在Python中安装PyPDF2库&#xff0c;您可以使用pip包管理器。打开您的命令行工具&#xff08;例如CMD、Terminal或Anaconda Prompt&#xff09;&#xff0c;然后输入以下命令&#xff1a; pip install PyPDF2 如果您使用的是Python 3&#xff0c;并且系统中…

计算机网络基本架构知识点

1. 网络体系结构模型&#xff1a; - OSI 七层模型&#xff1a; - 物理层&#xff1a;是网络通信的基础层&#xff0c;负责在物理介质上传输比特流。该层定义了物理连接的标准&#xff0c;如电缆的类型、接口的形状、插头的规格等&#xff0c;以及信号的传输方式&#xff0c;包括…