c语言链表实现

ops/2024/10/17 21:58:40/

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

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.ppmy.cn/ops/124780.html

相关文章

NVM 切换Node.js版本工具

大家好我是苏麟&#xff0c;今天聊聊NVM切换版本工具。 切换 node 版本工具 &#xff1a; GitHub - nvm-sh/nvm: Node Version Manager - POSIX-compliant bash script to manage multiple active node.js versions 查看node版本 node -v 查看 nvm 版本 nvm -v 查看可安装的Nod…

【Vue】Vue 快速教程

Vue tutorial 参考&#xff1a;教程 | Vue.js (vuejs.org) 该教程需要前置知识&#xff1a;HTML, CSS, JavaScript 学习前置知识&#xff0c;你可以去 MDN Vue framework 是一个 JavaScript framework&#xff0c;以下简称 Vue&#xff0c;下面是它的特点 声明式渲染&#xff…

Dify实现text2sql工作流[SQL调用篇],并查询Postgres数据库 or Mysql数据库(docker容器)

Dify 实现text2sql,查询Postgres数据库 1.Postgres数据库设置 1.1.docker-compose.yml修改 为了让 sandbox 容器能够与 docker-db-1 容器互相通信,你需要确保几个条件得到满足: 网络配置:确保 sandbox 和 db 都位于同一个 Docker 网络中。如果它们不在同一个网络中,数据…

《Spring Cloud 微服务:构建高效、灵活的分布式系统》

《Spring Cloud 微服务&#xff1a;构建高效、灵活的分布式系统》 一、引言 在当今快速发展的数字化时代&#xff0c;软件系统的规模和复杂性不断增加。为了应对这种挑战&#xff0c;微服务架构应运而生。Spring Cloud 作为构建微服务架构的强大工具集&#xff0c;提供了一系…

0x12 Dapr Dashboard configurations 未授权访问漏洞 CVE-2022-38817

参考: Dapr Dashboard configurations 未授权访问漏洞 CVE-2022-38817 | PeiQi文库 (wgpsec.org)免责声明 欢迎访问我的博客。以下内容仅供教育和信息用途: 合法性:我不支持或鼓励非法活动。请确保遵守法律法规。信息准确性:尽管我尽力提供准确的信息,但不保证其完全准确…

java-实现一个简单的httpserver-0.5.0

背景 通常写了一些接口&#xff0c;需要通过临时的http访问&#xff0c;又不需要spring这么厚重的框架 功能 设置并发监控并发两个get请求一个是根路径&#xff0c;一个是other 具体代码 import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.Http…

git error: You have not concluded your merge (MERGE_HEAD exists).

本地作了修改并提交远程&#xff0c;但管理员并未合并。此时本地又作了修改&#xff0c;而管理员合并了其它分支&#xff0c;且这个合并分支同时修改了当前本地分支共同的文件。本着提交前同步最新远程代码的原则&#xff0c;结果在合并远程分支时冲突了。其实解决这个冲突再合…

影刀RPA实战:Excel密码与字典功能指令

1.实战目标 本次主要讲解下影刀RPA操作Excel密码保护和数据列生成字典&#xff0c;在工作中&#xff0c;我们经常会遇到合作公司给我们发的表格&#xff0c;或是电商平台下载订单Excel数据表都带有密码&#xff0c;这在自动化处理过程中&#xff0c;多少带来不变&#xff0c;影…