“ 关注hahaCoder 获取最新资讯”
直播提醒
我将在2021.11.7
下午2:30
进行一次直播,手把手教大家2小时内通过C
语言编写一个学生管理系统,包括学生信息的增删改查等8个功能模块,其所用到的知识点包括指针、结构体、链表等,届时欢迎各位小伙伴们来我的直播间围观!
概述
本文是《C
语言程序设计》系列教程的最后一篇文章,我将结合指针
、结构体
、链表
来完成一个学生管理系统,其功能包括 建立学生信息、顺序输出学生信息、逆序输出学生信息、插入学生信息、删除学生信息、修改学生信息、查找学生信息 以及 清空学生信息。
「注」:本案例通过单向链表来实现。
链表概述
链表由节点组成,每个节点中包含两个域,分别是
数据域
和指针域
,本案例中数据域通过结构体实现,用来存储学生的姓名、学号、年龄;指针域用来存储下一个节点的地址。链表是一种线性表,线性表包含两种存储方式:顺序存储(数组)和链式存储(链表)。
功能拆分
建立链表
遍历链表(顺序遍历、逆序遍历)
插入节点(头节点、尾节点、任意节点)
删除节点(头节点、尾节点、任意节点)
修改节点信息
查找节点
清空链表
功能1:建立学生信息
思路:通过malloc
函数申请内存空间,并逐个添加链表节点,注意,单链表中最后一个节点的指针域为空,即next
指向的值为NULL
。
struct student *createList(){
struct student *head;//头节点
struct student *p1;//开辟新节点
struct student *p2;//与p1连接
int num1;
char name1[20];
int age1;
head = NULL;
int count = 1;
printf("请输入第1个学生的学号、姓名、年龄(用空格分隔):");
scanf("%d%s%d",&num1,&name1,&age1);
while(age1>0){
p1 = (struct student*)malloc(sizeof(struct student));
p1->num = num1;
strcpy(p1->name,name1);
p1->age = age1;
p1->next = NULL;
if(head == NULL){
head = p1;
}else{
p2->next = p1;
}
p2 = p1;
printf("请输入第%d个学生的学号、姓名、年龄(用空格分隔):",++count);
scanf("%d%s%d",&num1,&name1,&age1);
}
return head;
}
功能2:顺序输出学生信息
思路:对单链表进行遍历操作。
void displayList(struct student *head){
struct student *p;
int n = 0;
if(head!=NULL){
printf("顺序输出链表中学生信息如下:\n");
for(p=head;p!=NULL;p=p->next){
printf("学号:%-6d 姓名:%-20s 年龄:%-6.1d\n",p->num,p->name,p->age);
n++;
}
printf("学生总数:%d\n",n);
}else{
printf("空链表!\n");
}
}
功能3:逆序输出学生信息
思路:
借助递归
借助栈
修改单链表指向
struct student *reverseList(struct student *head){
/*
1. 借助递归
*/
/*
struct student *p;
p = head;
if(p!=NULL){
reverseList(p->next);
printf("学号:%-6d 姓名:%-20s 年龄:%-6.1d\n",p->num,p->name,p->age);
}
*/
/*
2. 借助栈
*/
struct student *p;
p = head;
stack<int> s;
while(p!=NULL){
s.push(p->num);
p = p->next;
}
while(!s.empty()){
p = head;
while(s.top()!=p->num){
p = p->next;
}
if(s.top()==p->num){
printf("学号:%-6d 姓名:%-20s 年龄:%-6.1d\n",p->num,p->name,p->age);
}
s.pop();
}
return head;
/*
3. 改变单链表指针指向
改变指针指向后,原链表也会被修改
*/
/*
struct student *pre;
struct student *post;
struct student *p;
pre = NULL;
post = NULL;
while(head!=NULL){
post = head->next;
head->next = pre;
pre = head;
head = post;
}
return pre;
*/
}
功能4:插入学生信息
思路:
插入头节点
插入任意节点
插入尾节点
struct student *insertNodes(struct student *head){
struct student *p;//待插入节点
struct student *p1;//待插入节点的前驱节点
struct student *p2;//待插入节点的后继节点
p2 = head;
p = (struct student *)malloc(sizeof(struct student));
printf("请输入要加入学生的学号、姓名、年龄:");
scanf("%d%s%d",&p->num,&p->name,&p->age);
if(head == NULL){ //若为空链表,则相当于创建一个新节点
head = p;
p->next = NULL;
}else{
while(p->num > p2->num&&p2->next!=NULL){ //查找待插入的位置
p1 = p2;
p2 = p2->next;
}
if(p->num < p2->num){ //头节点和中间任意节点的插入
if(p2 == head){ //头节点
head = p;
p->next = p2;
}else{ // 中间任意节点
p1->next = p;
p->next = p2;
}
}else{//尾节点的插入
p2->next = p;
p->next = NULL;
}
}
return head;
}
功能5:删除学生信息
思路:
删除头节点
删除任意节点
删除尾节点
struct student *deleteNodes(struct student *head){
struct student *p1;
struct student *p2;
int num2;//要删除学生的学号
printf("请输入要删除学生的学号:");
scanf("%d",&num2);
if(head == NULL){
printf("链表为空\n");
return head;
}
p2 = head;
while(num2!=p2->num&&p2->next!=NULL){ //查找要删除的节点
p1 = p2;
p2 = p2->next;
}
if(num2 == p2->num){
if(p2 == head){ //要删除的是头节点
head = p2->next;
}else{ //其他节点
p1->next = p2->next;
}
free(p2);
printf("删除了学号为%d的学生信息!\n",num2);
}else{
printf("该生不存在!\n");
}
return head;
}
功能6:修改学生信息
思路:查找并修改
void modify_student_info(struct student *head){
struct student *p;
int num;
char name[20];
int age;
printf("请输入您要修改学生的学号:");
scanf("%d",&num);
p = head;
if(head!=NULL){
while(p->num!=num&&p->next!=NULL){
p = p->next;
}
if(p->num==num){
printf("请输入您要更改后的信息:\n");
scanf("%d%s%d",&num,&name,&age);
p->num = num;
strcpy(p->name,name);
p->age = age;
}else{
printf("没有找到学号为%d的学生信息,请确认学号信息是否正确!\n");
}
}else{
printf("空链表\n");
}
}
功能7:查找学生信息
思路:查找并遍历
void search_student_info(struct student *head){
struct student *p;
int num;//要查找对应学生的学号信息
printf("请输入要查找学生的学号:");
scanf("%d",&num);
p = head;
//非空链表的情况下
if(head != NULL){
while(p->num!=num&&p->next!=NULL){
p=p->next;
}
//不满足while循环的第一个条件
if(p->num==num){
printf("你所查找的学号为%d的学生信息如下:\n",num);
printf("学号:%-6d 姓名:%-20s 年龄:%-6.1d\n",p->num,p->name,p->age);
}else{
//不满足while循环的最后一个条件
printf("没有找到学号为%d的学生信息,请确认学号是否正确!\n",num);
}
}else{//空链表的情况
printf("空链表!");
}
}
功能8:清空学生信息
思路:清空或销毁链表
struct student *destroyList(struct student *head){
struct student *p,*q;
if(head==NULL){
printf("空链表!\n");
}
p = head->next;
while(p!=NULL){
q = p->next;
free(p);
p = q;
}
printf("信息删除完毕!\n");
head = NULL;
return head;
}
项目进阶
单向循环链表
双向链表
双向循环链表
获取课件
2021.11.7
下午2:30
直播完成后,我会将课件上传至百度网盘,大家在微信公众号后台回复「C
语言直播」获取链接,即可下载!