C语言单链表讲解(上):有表头链表的使用
目录
前言
单链表的分类
有表头单链表
一、create()创建链表,后面产生的结构体将放在表头后面
二、newNote()创建节点,读取用户输入的记录,生成结构体数据
三、insert()从表头插入新的数据,可用于添加信息的功能。
四、query()通过接收用户的编号来查找链表中对应的记录,但只能返回第一个编号相同的记录
五、query a record()查找函数,可用于查找信息功能
六、delete()用于删除第一个与编号相同的记录
八、sort()按编号排序,用于信息排序,经典的冒泡排序法
九、display()用于信息显示
十、Reverse()链表逆置
完整代码展示
前言
在我们学习C语言基础的过程中,指针和链表一直是新手的两大拦路虎。在大学的程序语言课程设计中,我们在设计系统时可能会用到链表或者结构体数组。今天,我想为大家梳理一下关于单链表的使用。本文章需要读者先行理解C语言的结构体和结构体中next的使用。
注:我所使用的是vs2019,部分代码可能在其他编译器中会报错。
单链表的分类
在我理解中,单链表分为两类,一种是有表头单链表,一种是无表头单链表。本章我先来帮助大家理解有表头单链表。
结构体框架
struct Structure //为了方便大家理解char类型和int类型在使用上的区别,我特地分别设置了两个变量
{char num[4];//编号int score;//分数char name[10];//姓名int room;//房间号struct Structure* next;
};
有表头单链表
有表头单链表,顾名思义,就是创建的链表中表头数据为NULL,next直接指向下一结构体。它包含的基础功能有:添加信息,查找信息,删除信息,信息排序,文件操作,信息显示。文件操作功能我暂且放在下一章讲解。
下面,我来讲解使用有表头单链表需要使用到的函数:
一、create()创建链表,后面产生的结构体将放在表头后面
struct Structure* create()//创建有表头链表(不存数据)
{struct Structure* head = (struct Structure*)malloc(sizeof(struct Structure));//产生变量head->next = NULL;//初始化变量return head;
}
我们需要在主函数main中编写 struct Structure* head = create(); 这样一个链表的表头就形成了。
二、newNote()创建节点,读取用户输入的记录,生成结构体数据
struct Structure* newNote()//创建节点
{struct Structure* p = (struct Structure*)malloc(sizeof(struct Structure));scanf_s("%s%d%s%d", p->num, 4, &p->score, p->name, 10, &p->room);p->next = NULL;return p;
}
scanf_s代码解释: // scanf_s("%s%d%s%d", p->num, 4, &p->score, p->name, 10, &p->room);
1.代码解读:num和name均为char类型的数组变量,在取址时可以不用添加“&”,后面跟着的4,10为可读取数据的长度。score和room为int类型变量,需添加“&”读取地址
2.这是vs新版本中为了保证系统的安全,添加了检验机制。
3.它与scanf的区别在于,读取字符串时可以确定读取的长度,当输入字符串长度过长时可以直接对该变量赋值为空,且不影响后续数据的读取。若输入数据为123456 78 张三 101,则存储的数据为:num="" score=78 name="张三" room=101 。
函数解读,创建一个结构体,并存储用户输入数据,并将该结构体返回。
三、insert()从表头插入新的数据,可用于添加信息的功能。
void insert(struct Structure* head)//调用创建节点导入数据并从表头插入
{int n;//用于读取用户输入的记录个数printf("请输入你要录入的学生个数:");scanf_s("%d", &n);for (; n < 1; n--){printf("请输入数据\n");//也可以定义变量i来提示用户当前输入的记录条数struct Structure* node = newNote();node->next = head->next;head->next = node;}
}
将用户输入的记录一个个从表头插入链表中。
四、query()通过接收用户的编号来查找链表中对应的记录,但只能返回第一个编号相同的记录
Structure* Query(Structure* head, char* num)//查找编号,有则返回对应结构体,否则返回空链表
{Structure* p;p = head;while (p != NULL){if (strcmp(num, p->num) == 0) return p;p = p->next;}return NULL;
}
本函数中使用了strcmp()函数,需使用头文件#include<string.h>。常用于比较两个字符串的大小,当两种相同时则返回数值0。
本函数从表头开始查找,编号相同则返回,直到查找到链表尾步为止,若无对应编号则返回空值。
常被query a record查找函数和delete删除函数调用。
五、query a record()查找函数,可用于查找信息功能
void Query_a_record(Structure* head)//接收查找反馈并展示结果
{char s[4];Structure* p;printf("请输入一个要查找的编号\t");scanf_s("%s", s, 4);getchar();p = Query(head, s);if (p != NULL){printf("%s %d %s %d", p->num, p->score, p->name, p->room);system("pause");}else{printf("找不到对应的编号!\t\t");system("pause");}
}
调用query查找函数,分两种情况,若查找到记录则显示;若返回值为空则链表没有该编号。
缺点:无法判断链表是否存储数据
六、delete()用于删除第一个与编号相同的记录
Telephone* Delete(Telephone* head, char* num)//接收数据,并删除编号相同的记录
{Telephone* p1, * p2=NULL;p1 = head;while ((strcmp(num, p1->num) != 0) && (p1->next != NULL)){p2 = p1; p1 = p1->next;}if (strcmp(num, p1->num) == 0){if (p1 == head) head = p1->next;else p2->next = p1->next;free(p1);}return head;
}
用于接收来自delete a record删除函数传递的编号,然后删除第一个与之编号相同的记录
缺点:只能删除一个
七、delete a record()用于删除信息功能,删除查询的记录
Structure* Delete_a_record(Structure* head)//传递要删除的记录编号,并选择是否删除
{char s[4];printf("请输入你要删除的编号:\t");scanf_s("%s", s, 4);getchar();if (Query(head, s) != NULL){ head = Delete(head, s);printf("编号为%s的记录已删除", s);system("pause");}else{printf("编号为%s的记录未查询到", s);system("pause");}return head;
}
通过调用query查找函数来确定编号是否存在,然后调用delete删除函数来删除记录。
八、sort()按编号排序,用于信息排序,经典的冒泡排序法
void sort(struct Structure* head)//排序
{int i, j, n = 0;Structure t, * p = head, * p1, * p2;while (p != NULL)//统计结构体数量{n++;p = p->next;}p2 = head;for (i = 0; i < n - 1; i++){p1 = p2->next;p = p2;for (j = i + 1; j < n; j++){if (strcmp(p1->num, p->num) < 0) p = p1;p1 = p1->next;}if (p != p2){strcpy(t.num, p2->num);strcpy(t.name, p2->name);t.room = p2->room;t.score = p2->score;strcpy(p2->num, p->num);strcpy(p2->name, p->name);p2->room = p->room;p2->score = p->score;strcpy(p->num, t.num);strcpy(p->name, t.name);p->room = t.room;p->score = t.score;}p2 = p2->next;}printf("升序排列操作已完成!\t");system("pause");
}
t是结构体变量,是交换的载体。而p1,p2是结构体指针。所以在调用结构体成员时,t使用".",p1使用"->"。
九、display()用于信息显示
void Display(Structure* head)//显示记录
{Structure* p = head;printf("编号\t\t成绩\t\t姓名\t\t教室\n");p = p->next;//跳过表头while (p != NULL){printf("%s\t\t%d\t\t%s\t\t%d\n", p->num, p->score, p->name, p->room);p = p->next;}system("pause");
}
十、Reverse()链表逆置
不知道怎么说,读者可以通过画图自行体会
Structure* Reverse(Structure* head)
{Structure* p1, * p2, *p3;p3 = head->next;p1 = p3->next;p3->next = NULL;while (p1 != NULL){p2 = p1; p1 = p1->next;p2->next = p3; p3 = p2;}head->next = p3;return head;
}
完整代码展示
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//为了方便大家理解char类型和int类型在使用上的区别,我特地分别设置了两个变量
struct Structure
{char num[4];//编号int score;//分数char name[10];//姓名int room;//房间号struct Structure* next;
};
//创建有表头链表(不存数据)
struct Structure* create()
{struct Structure* head = (struct Structure*)malloc(sizeof(struct Structure));//产生变量head->next = NULL;//初始化变量return head;
}
//创建节点
struct Structure* newNote()
{struct Structure* p = (struct Structure*)malloc(sizeof(struct Structure));scanf_s("%s%d%s%d", p->num, 4, &p->score, p->name, 10, &p->room);p->next = NULL;return p;
}
//调用创建节点导入数据并从表头插入
void insert(struct Structure* head)
{int n;//用于读取用户输入的记录个数printf("请输入你要录入的学生个数:");scanf_s("%d", &n);for (; n > 0; n--){printf("请输入数据\n");//也可以定义变量i来提示用户当前输入的记录条数struct Structure* node = newNote();node->next = head->next;head->next = node;}
}
//查找编号,有则返回对应结构体,否则返回空链表
Structure* Query(Structure* head, char* num)
{Structure* p;p = head;while (p != NULL){if (strcmp(num, p->num) == 0) return p;p = p->next;}return NULL;
}
//接收查找反馈并展示结果
void Query_a_record(Structure* head)//接收查找反馈并展示结果
{char s[4];Structure* p;printf("请输入一个要查找的编号\t");scanf_s("%s", s, 4);getchar();p = Query(head, s);if (p != NULL){printf("%s %d %s %d", p->num, p->score, p->name, p->room);system("pause");}else{printf("找不到对应的编号!\t\t");system("pause");}
}
//接收数据,并删除编号相同的记录
Structure* Delete(Structure* head, char* num)
{Structure* p1, * p2 = NULL;p1 = head;while ((strcmp(num, p1->num) != 0) && (p1->next != NULL)){p2 = p1; p1 = p1->next;}if (strcmp(num, p1->num) == 0){if (p1 == head) head = p1->next;else p2->next = p1->next;free(p1);}return head;
}
//传递要删除的记录编号,并选择是否删除
Structure* Delete_a_record(Structure* head)
{char s[4];printf("请输入你要删除的编号:\t");scanf_s("%s", s, 4);getchar();if (Query(head, s) != NULL){ head = Delete(head, s);printf("编号为%s的记录已删除", s);system("pause");}else{printf("编号为%s的记录未查询到", s);system("pause");}return head;
}
//排序
void sort(struct Structure* head)
{int i, j, n = 0;Structure t, * p = head, * p1, * p2;while (p != NULL)//统计结构体数量{n++;p = p->next;}p2 = head;for (i = 0; i < n - 1; i++){p1 = p2->next;p = p2;for (j = i + 1; j < n; j++){if (strcmp(p1->num, p->num) < 0) p = p1;p1 = p1->next;}if (p != p2){strcpy(t.num, p2->num);strcpy(t.name, p2->name);t.room = p2->room;t.score = p2->score;strcpy(p2->num, p->num);strcpy(p2->name, p->name);p2->room = p->room;p2->score = p->score;strcpy(p->num, t.num);strcpy(p->name, t.name);p->room = t.room;p->score = t.score;}p2 = p2->next;}printf("升序排列操作已完成!\t");system("pause");
}
//显示记录
void Display(Structure* head)
{Structure* p = head;printf("编号\t\t成绩\t\t姓名\t\t教室\n");p = p->next;//跳过表头while (p != NULL){printf("%s\t\t%d\t\t%s\t\t%d\n", p->num, p->score, p->name, p->room);p = p->next;}system("pause");
}
void Display_Main_Menu()
{printf("1.添加信息\n");printf("2.删除信息\n");printf("3.查找信息\n");printf("4.排序信息\n");printf("5.显示信息\n");printf("0.退出系统\n");
}
int main()
{int choose, b;struct Structure* head = create();while (1){Display_Main_Menu();scanf_s("%d", &choose);switch (choose){case 1:insert(head);system("cls");break;case 2:Delete_a_record(head);system("cls");break;case 3:Query_a_record(head);system("cls");break;case 4:sort(head);system("cls");break;case 5:Display(head);system("cls");break;case 0:goto loop;default:printf("\t请输入选项0—9!\n");system("pause");}}
loop:printf("感谢本次使用成绩处理系统\n");system("pause");
}
C语言单链表讲解(上):有表头链表的使用相关推荐
- 数据结构——链表讲解(1)
作者:几冬雪来 时间:2023年3月3日 内容:数据结构链表讲解 目录 前言: 链表的概念: 1.为什么要有链表: 2.链表的运行原理: 3.链表的形态多少: 4.单链表的代码书写: 1.创建文件: ...
- c语言单链表倒置(附原理讲解)
c语言单链表倒置 今天博主,讲一个单链表倒置的例子,事实上 话不多说,我们直接上代码,待会会给大家讲解倒置算法实现原理 #include<stdio.h> #include<stdl ...
- 链式存储【C语言单链表】
文章目录 单链表 单链表的结构 需要的头文件 申请节点 单链表尾插 单链表头插 单链表尾删 单链表头删 单链表查找 单链表在(pos之前/pos之后)插入数据 单链表删除(pos/pos之后)数据 单 ...
- c语言单链表设计报告,单链表实验报告
<数据结构>实验报告二 分校: 学号: 日期: 班级: 姓名: 程序名: L2311.CPP 一.上机实验的问题和要求: 单链表的查找.插入与删除.设计算法,实现线性结构上的单链表的产生以 ...
- C语言单链表基本操作总结
C语言单链表基本操作 本文是参考他人实现的C语言单链表,对多篇博文整理的结果,仅作为学习笔记.文末有参考出处. 1.单链表定义 链表是通过一组任意的存储单元来存储线性表中的数据元素,这些存储单 ...
- C语言单链表实现19个功能完全详解
#include "stdafx.h" #include "stdio.h" #include <stdlib.h> #include " ...
- 数据结构中单链表的存储c语言,单链表一 - 数据结构与算法教程 - C语言网
1. 单链表概念&设计 单链表是一种链式存取的数据结构,,链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指 ...
- C语言一趟冒泡交换最小值,C语言单链表冒泡排序为啥以下代码实现不了?
struct node *sort(struct node *head)/*排序*/ { struct node *p,*q; struct node *temp; for(p=head;p!=NUL ...
- c语言单链表功能,[数据结构]单链表(C语言)的各种功能
06-03阅读200,000 + 链表是一种常见的基本数据结构,在此充分利用了结构指针. 链表可以动态存储和分配,即链表是一个功能非常强大的数组. 他可以在节点中定义多种数据类型,并可以根据需要随意添 ...
最新文章
- 服务器状态监控之二软硬件环境介绍
- 罗永浩直播间再回应直播售假:全方位整改 成立质控实验室
- java基础环境搭建_java基础环境搭建
- ajax调用后台Datatable
- Eclipse 4.7(Oxygen)安装Tomcat Plugin 后没有小猫图标解决方法
- VS2017下载安装
- c++哈利波特编程代码
- 腾讯 AI Lab 2021 年度回顾
- 多线程启动停止暂停继续
- 替代A4988的微型打印机驱动TMI8421国产电机驱动芯片
- 硬件工程师入门基础知识(一)基础元器件认识(一)
- 【SQL武林秘籍】零基础带你快速上手SQL语言
- ANSYS Workbench中多场耦合下不同模块间的信息共享设置
- pbx_extension_helper: No application ‘Macro‘ for extension (from-internal, h, 1)
- 小米路由hd php,详谈小米路由器Pro / HD,俩都是…
- XNA入门/框架介绍
- python内置函数返回序列中最大元素_Python 内置函数 ____________ 用来返回序列中的最大元素。_学小易找答案...
- java文件名加时间戳_Java处理文件名加时间戳
- 戴维南定理(Thevenin‘s theorem)
- Trace Related