链表:由独立的节点组成(物理上不连续),各节点之间通过指针域连接,达到逻辑上的连续
节点由两部分组成:数据域、指针域
数据域:存放数据
指针域:保存下一个节点的地址编号
typedef struct stu
{
/*既然是学生信息管理系统,首先来了解下学生有啥信息
学生有学号、姓名、分数,还有年龄和性别等等,其他的就不搞了挺多的,基本都差不多*/
// 数据域
int num; // num代表学生的学号
char name[32]; // 字符数组name代表学生的姓名
char sex[18]; // sex代表学生的性别
int age; // age表示学生的年龄
float score; // score代表学生的分数
// 指针域
struct stu *next; // 保存下一个节点的信息
} STU;
我写了一个单向的动态链表作为学生信息管理系统的技术支持
链表说白了,由若干个节点组成,每一个节点都是一个结构体(如上结构体STU代码)和结构体的每一个成员对应的数据,加在一块儿就成了一个链表节点信息。
废话不多说,上干货,瞧瞧我花了四个小时弄好的代码程序,哇哈哈哈!!!
先别急!!!
我分了三个文件,见上图
这是main.c文件,系统调用主程序入口
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "link.h"
STU *head = NULL;
void help(void)
{
printf("************************************************\n");
printf(" 学生信息管理系统 \n");
printf("各个指令及其功能说明 \n");
printf("1.help: 帮助信息 \n");
printf("2.quit: 退出进程 \n");
printf("3.insert: 插入链表节点 \n");
printf("4.printf: 遍历链表节点 \n");
printf("5.search: 查询链表节点 \n");
printf("6.delete: 删除链表节点 \n");
printf("7.free: 释放整个链表 \n");
printf("8.reverse: 链表的逆序 \n");
printf("9.sort: 链表的排序 \n");
printf("************************************************ \n");
}
int main(int argc, char const *argv[])
{
printf("欢迎访问学生信息管理系统\n");
printf("该系统提供了学生学号、姓名等相关信息存储和查询等功能,如需帮助请键入 “help” 指令\n");
while (1)
{
char cmd[32] = "";
printf("请输入操作指令:");
scanf("%s", cmd);
if (strcmp(cmd, "insert") == 0)
{
printf("请输入要插入的学生信息(学号、姓名、性别、年龄、分数): ");
STU temp;
scanf("%d %s %s %d %f", &temp.num, temp.name, temp.sex, &temp.age, &temp.score);
// 将temp的数据插入到堆区链表中
head = insert_link(head, temp); // 每次更新head的指向
}
else if (strcmp(cmd, "printf") == 0)
{
printf_link(head);
}
else if (strcmp(cmd, "search") == 0)
{
printf("该学生管理查询系统目前仅仅提供根据学号查询学生的相关信息\n");
printf("如有需求,可自行完善\n");
printf("****************************\n");
printf("\n");
printf("请输入要查询的学号:");
int num = 0;
scanf("%d", &num);
STU *ret = serach_link(head, num);
if (ret != NULL)
{
printf("查询结果:%d %s %s %d %f\n", ret->num, ret->name, ret->sex, ret->age, ret->score);
}
}
else if (strcmp(cmd, "delete") == 0)
{
printf("该学生管理查询系统目前仅仅提供根据<<姓名>>删除学生的相关信息\n");
printf("如有需求,可自行完善\n");
printf("****************************\n");
printf("\n");
printf("请输入需要删除的姓名:");
char name[32] = "";
scanf("%s", name);
head = delete_link(head, name);
}
else if (strcmp(cmd, "free") == 0)
{
printf("请稍后,正在清空链表信息......\n");
sleep(1);
head = free_link(head);
}
else if (strcmp(cmd, "reverse") == 0)
{
printf("正在逆序排序中,请稍后......\n");
sleep(1);
head = reverse_link(head);
}
else if (strcmp(cmd, "sort") == 0)
{
printf("正在按照从小到大的分数排序中,请稍后......\n");
sleep(1);
sort_link(head);
}
else if (strcmp(cmd, "help") == 0)
{
printf("欢迎您访问学生信息管理系统帮助手册\n");
sleep(1);
help();
}
else if (strcmp(cmd, "quit") == 0)
{
printf("请稍后,正在清空链表信息......\n");
sleep(1);
head = free_link(head);
printf("学生信息管理系统已经退出\n");
printf("欢迎下次光临\n");
sleep(1);
printf("再见!!!\n");
break;
}
else
{
printf("输入的指令有误,请重新输入!");
}
}
return 0;
}
这是link.h文件,是link.c文件的头文件
#ifndef __LINK_H__
#define __LINK_H__
typedef struct stu
{
/*既然是学生信息管理系统,首先来了解下学生有啥信息
学生有学号、姓名、分数,还有年龄和性别等等,其他的就不搞了挺多的,基本都差不多*/
// 数据域
int num; // num代表学生的学号
char name[32]; // 字符数组name代表学生的姓名
char sex[18]; // sex代表学生的性别
int age; // age表示学生的年龄
float score; // score代表学生的分数
// 指针域
struct stu *next; // 保存下一个节点的信息
} STU;
extern STU *insert_link(STU *head, STU temp);
extern void printf_link(STU *head); // 遍历链表信息
extern STU *serach_link(STU *head, int num); // 按照学号查找链表信息
extern STU *delete_link(STU *head, char *name); // 根据姓名删除学生信息
extern STU *free_link(STU *head); // 释放整个链表信息
extern STU *reverse_link(STU *head); // 链表的逆序
extern void sort_link(STU *head); // 按照学生的分数从小到大进行排序
#endif
这是link.c文件,功能的实现都在这儿,最最最重要的部分,哇哈哈哈!!!
#include "link.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// link单向动态链表提供了三种插入方式
/*第一种,是在head头部之前插入数据
第二种,是在link单向动态链表的尾部插入数据
第三种,是按照学生的学号从小到大有序插入*/
#if 0
//头部之前插入数据
STU *insert_link(STU *head,STU temp)
{
//1、先申请插入的节点p1堆区空间并将数据复制到该空间内
STU *p1=(STU *)calloc(1,sizeof(STU));
*p1=temp;
p1->next=NULL;
//2、判断链表是否存在
if(NULL==head)
{
head=p1;
return head;
}
else
{
p1->netx=head;
head=p1;
return head;//及时更新头部信息
}
}
#endif
#if 0
//尾部插入数据
STU *insert_link(STU *head,STU temp)
{
//1、先申请插入的节点p2堆区空间并将数据复制到该空间内
STU *p2=(STU *)calloc(1,sizeof(STU));
*p2=temp;
p2->next=NULL;
//2、判断链表是否存在
if(NULL==head)
{
head=p2;
return head;
}
else
{
//3、寻找尾部节点
STU *prev=head;
while(prev->next!=NULL)
{
prev=prev->next;
}
//插入尾部节点
prev->next=p2;
}
return head;//及时更新头部信息
}
#endif
#if 1
// 按照学号有序插入
STU *insert_link(STU *head, STU temp)
{
// 1、为插入的数据申请堆区空间并并将数据复制到堆区空间内
STU *p3 = (STU *)calloc(1, sizeof(STU));
*p3 = temp;
p3->next = NULL;
// 2、判断链表是否存在
if (NULL == head)
{
head = p3;
return head;
}
else
{
// 3、建立链表上一个节点和下一个节点指针,并建立关系
STU *prev, *pnext;
prev = pnext = head;
while ((pnext->num < p3->num) && (pnext->next != NULL)) //
{
prev = pnext;
pnext = pnext->next; // 让prev永远指向pnext的上一个节点
}
// 4、寻找插入点
if (pnext->num > p3->num) // 前、中部插入
{
if (pnext == head) // 前部插入
{
p3->next = head;
head = p3;
return head;
}
else // 中间插入
{
prev->next = p3;
p3->next = pnext;
}
}
else // 尾部插入
{
pnext->next = p3;
}
}
return head;
}
#endif
void printf_link(STU *head) // 遍历链表信息
{
// 1、先判断链表是否存在
if (NULL == head)
{
printf("The linked list does not exist\n");
return;
}
STU *pnext = head;
while (pnext != NULL)
{
printf("%d %s %s %d %f ", pnext->num, pnext->name, pnext->sex, pnext->age, pnext->score);
// 将pnext移动到下一个节点继续遍历
pnext = pnext->next;
printf("\n");
}
printf("\n");
return;
}
STU *serach_link(STU *head, int num) // 按照学号查找链表信息
{
// 老规矩先判断链表是否存在
if (NULL == head)
{
printf("The linked list does not exist\n");
return NULL;
}
else
{
// 逐个节点查找学号
STU *pnext = head;
while ((pnext->num != num) && (pnext->next != NULL)) // while循环查找num
{
pnext = pnext->next;
}
// 找到该学号
if (pnext->num == num)
{
return pnext;
}
else
{
printf("链表中不存在该学号信息\n");
}
}
return NULL;
}
STU *delete_link(STU *head, char *name) // 根据姓名删除学生信息
{
// 先判断链表是否存在
if (NULL == head)
{
printf("The Linked list does not exit\n");
return NULL;
}
else
{
// 先建立上一个节点和下一个节点的信息和关系
STU *prev, *pnext;
prev = pnext = head;
while ((strcmp(pnext->name, name) != 0) && (pnext->next != NULL))
{
prev = pnext;
pnext = pnext->next;
}
// 寻找要删除的节点
if (strcmp(pnext->name, name) == 0)
{
// 判断节点是否是head
if (pnext == head)
{
head = pnext->next;
free(pnext); // 删除节点
return head;
}
else
{
prev->next = pnext->next;
free(pnext);
}
printf("姓名为%s的学生信息已经全部删除\n", name);
}
else
{
printf("没有找到要删除的学生\n");
}
}
return head;
}
STU *free_link(STU *head) // 释放整个链表信息
{
// 先判断链表是否存在
if (NULL == head)
{
printf("The Linked list does not exit\n");
return NULL;
}
else
{
// 逐个释放链表节点
STU *pnext = head;
while (pnext != NULL)
{
// 让head保存下一个节点的位置
head = pnext->next;
free(pnext);
pnext = head; // 然后让pnext指向下一个节点
}
printf("链表信息已经清空!!!\n");
}
return head;
}
STU *reverse_link(STU *head) // 链表的逆序
{
// 先判断链表是否存在
if (NULL == head)
{
printf("The Linked list does not exit\n");
return NULL;
}
else
{
STU *pnext, *phead;
pnext = head->next; // 让pnext保存head的下一个节点
head->next = NULL;
while (pnext != NULL)
{
phead = pnext->next; // 让phead备份pnext的下一个节点信息
pnext->next = head; // 将pnext下一个节点变成了头
head = pnext; // 让pnext跑到head的位置
pnext = phead; // 然后将备份的pnext下一个节点信息放到pnext原来的位置
}
printf("整个链表逆序完成,请遍历查看\n");
}
return head;
}
void sort_link(STU *head) // 按照学生的分数从小到大进行排序
{
// 先判断链表是否存在
if (NULL == head)
{
printf("The Linked list does not exit\n");
return;
}
else
{
STU *p_i = head;
while (p_i->next != NULL)
{
STU *p_s = p_i; // 让p_s保存head的头部信息
STU *p_j = p_s->next; // 让p_j保存head的下一个信息
while (p_j != NULL)
{
if (p_s->score > p_j->score)
p_s = p_j;
p_j = p_j->next;
}
if (p_i != p_s) // 如果p_i和p_s两个指针指向不是同一个节点,也就是p_s指向变了
{
// 数据发生交换
STU temp = *p_i;
*p_i = *p_s;
*p_s = temp;
// 指针域也发生交换
temp.next = p_i->next; // 让temp指针来临时保存p_i的指针
p_i->next = p_s->next;
p_s->next = temp.next;
}
p_i = p_i->next; // 继续循环遍历
}
printf("整个链表排序完成,请遍历查看\n");
}
}
该项目实现了以链表存储学生的相关信息,提供插入、删除、查找、遍历和排序包括逆序等功能,
根据指令来调用相关的函数,实现对应功能。
上运行结果图
学生信息插入操作(五个信息啊,不能少不能多,想变化。。。。。。自己弄)
学生信息的查询和删除操作
学生信息的从小到大排序和逆序两个操作
学生信息清空和退出学生信息管理系统操作