#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#define RD_NO (1<<0)
#define RD_NAME (1<<1)
#define RD_SEX (1<<2)
#define RD_SCORE (1<<3)
//描述1个学生的属性
struct STUDENT
{
int no;
char name[64];
char sex;
float score;
};
//创建链表的节点数据结构
struct _node
{
struct STUDENT student;//该节点的数据域
struct _node *prev; //该节点的指针域 -- 保存上一个节点
struct _node *pnext; //该节点的指针域 -- 保存下一个节点
};
void GetInfo(struct STUDENT *p,unsigned char flag);
int Menu(void);
int Link_Add(struct _node *p1);
int ShowAll(struct _node *p1);
int Link_Find(struct _node*p1);
int Link_Change(struct _node *p1);
int Link_Del(struct _node *p1);
//指向头节点的指针变量
struct _node *phead = NULL;
int main()
{
int no;
while(1){
no= Menu();
switch(no)
{
case 1:Link_Add(phead);break;
case 2:Link_Del(phead);break;
case 3:Link_Change(phead);break;
case 4:Link_Find(phead);break;
case 5:break;
case 6:ShowAll(phead);break;
}
}
}
/*
菜单
参数:无
返回:输入的菜单选项
*/
int Menu(void)
{
int no;
p1:
printf("**学生管理系统**\n");
printf("1 添加学生 \n");
printf("2 删除学生 \n");
printf("3 修改学生 \n");
printf("4 查找学生 \n");
printf("5 成绩排序 \n");
printf("6 打印所有信息 \n");
printf("请输入选项:");
scanf("%d",&no);
if(no >= 1 && no <= 6)
return no;
printf("输入有误,重新输入\n");
goto p1;
}
/*
函数功能:给链表中添加新的新节点
参数:p1 -- 保存链表头的地址
返回值:0 -- 成功
>1 -- 失败
*/
/*
int Link_Add(struct _node *p1)
{
//1.开辟新的节点,使用pnew指向该新的节点
struct _node *pnew = malloc(sizeof(struct _node));
//2.1给节点的数据域赋值
GetInfo(&pnew->student,RD_NO|RD_NAME|RD_SEX|RD_SCORE);
//2.2给节点的指针域赋值
pnew->pnext = NULL;
//3.把新的节点添加到链表中去
//3.1 链表为空
if(phead == NULL){
phead = pnew;
return 0;
}else//尾插法
{
//找到链表尾 -- 根据节点的指针域是否为NULL
while(p1->pnext != NULL){
p1 = p1->pnext;
}
//把新节点添加到链表最后节点的后面(新的节点地址给上一个最后1个节点的指针域)
p1->pnext = pnew;
return 0;
}
}*/
/*
函数功能:给链表中添加新的新节点
参数:p1 -- 保存链表头的地址
返回值:0 -- 成功
>1 -- 失败
*/
/*
int Link_Add(struct _node *p1)
{
//1.开辟新的节点,使用pnew指向该新的节点
struct _node *pnew = malloc(sizeof(struct _node));
//2.1给节点的数据域赋值
GetInfo(&pnew->student,RD_NO|RD_NAME|RD_SEX|RD_SCORE);
//2.2给节点的指针域赋值
pnew->pnext = NULL;
//3.把新的节点添加到链表中去 -- 头插法
//3.1 原来第一个节点的地址给新节点的指针域
pnew->pnext = phead;
phead = pnew;
}*/
/*
函数功能:给链表中添加新的新节点
参数:p1 -- 保存链表头的地址
返回值:0 -- 成功
>1 -- 失败
*/
int Link_Add(struct _node *p1)
{
//1.开辟新的节点,使用pnew指向该新的节点
struct _node *pnew = malloc(sizeof(struct _node));
//2.1给节点的数据域赋值
GetInfo(&pnew->student,RD_NO|RD_NAME|RD_SEX|RD_SCORE);
//2.2给节点的指针域赋值
pnew->pnext = NULL;
pnew->prev = NULL;
//3.把新的节点添加到链表中去 -- 中间插入
//3.1 是否为空链表
if(phead == NULL){
phead = pnew;//直接放到第一个节点位置
return 0;
}
//3.2 查找位置,进行插入
while(p1 != NULL){
if(pnew->student.no < phead->student.no)//上来比第一个节点数据小
{
phead->prev = pnew;
pnew->pnext = phead;
phead = pnew;
return 0;
}
if(pnew->student.no > p1->student.no){//中间
if(p1->pnext == NULL)//链表末尾
{
pnew->prev = p1;
p1->pnext = pnew;
}else if(pnew->student.no < p1->pnext->student.no)//中间
{ //修改插入节点的指针域
pnew->prev = p1;
pnew->pnext = p1->pnext;
//修改下一个节点(prev)
p1->pnext->prev = pnew;
//修改上一个节点(pnext)
p1->pnext = pnew;
return 0;
}
}
p1 = p1->pnext;
}
}
/*
函数功能:打印链表中所有节点信息
参数:链表头传递进来
返回值:0 -- 成功
>0 -- 失败
*/
int ShowAll(struct _node *p1)
{
printf("打印所有学生信息操作……\n");
printf("学号\t姓名\t性别\t成绩\n");
while(p1 != NULL){
printf("%d\t",p1->student.no);
printf("%s\t",p1->student.name);
printf("%c\t",p1->student.sex);
printf("%f\n",p1->student.score);
p1 = p1->pnext;
}
}
/*
从链表中查找某个信息
参数:p1 -- 链表头
返回值:0 -- 成功
>0 -- 失败
*/
int Link_Find(struct _node*p1)
{
struct STUDENT temp={0};//保存要查找的信息
GetInfo(&temp,RD_NO|RD_NAME);
//循环比较学号
while(p1 != NULL)
{
if(p1->student.no == temp.no){
if(strcmp(p1->student.name,temp.name)==0){
printf("找到该学生,信息如下:\n");
printf("%d\t",p1->student.no);
printf("%s\t",p1->student.name);
printf("%c\t",p1->student.sex);
printf("%f\n",p1->student.score);
return 0;
}else{
printf("学号正确,姓名不对\n");
}
}
p1 = p1->pnext;
}
printf("查无此人\n");
return 1;
}
/*
修改链表节点的内容
参数:p1 -- 指向链表头
返回值:0 -- 正确
>0 -- 错误
*/
int Link_Change(struct _node *p1)
{
struct STUDENT temp={0};
GetInfo(&temp,RD_NO|RD_NAME);
while(p1 != NULL){
if(p1->student.no == temp.no){
if(strcmp(p1->student.name,temp.name)==0){
GetInfo(&temp,RD_NO|RD_NAME|RD_SEX|RD_SCORE);
p1->student = temp;
return 0;
}
}
p1 = p1->pnext;
}
printf("查无此人\n");
return 1;
}
/*
删除链表中某个节点
p1 -- 链表头
返回值: 0 -- 成功
>0 -- 失败
1 -- 链表为空
2 -- 链表中查询不到
*/
int Link_Del(struct _node *p1)
{
if(p1 == NULL){//空链表
return 1;//链表为空
}
struct STUDENT temp={0};
GetInfo(&temp,RD_NO);
struct _node *pdel = NULL;//保存要删除节点的首地址
while(p1 != NULL){
if(p1->student.no == temp.no)
{
pdel = p1;//pdel保存要删除节点的首地址
if(pdel->prev == NULL && pdel->prev == NULL)
{
phead = NULL;
free(pdel);
return 0;
}
//前一个节点的pnext变化
if(pdel->prev != NULL)//中间
pdel->prev->pnext = pdel->pnext;
else//代表头节点
{
pdel->pnext->prev = NULL;//下一个节点的prev为空
phead = pdel->pnext; //下一个节点作为了链表头
}
//后一个节点的prev变化
if(pdel->pnext != NULL)
pdel->pnext->prev = pdel->prev;
else{
//上一给节点pnext变为NULL -- 作为链表尾
pdel->prev->pnext = NULL;
}
free(pdel);
return 0;
}
p1 = p1->pnext;
}
return 2;
}
/*
flag = 相应的选项是否允许输入
[0]位 -- no_flag 1--允许输入 0 -- 不允许输入
[1]位 -- name_flag 1--允许输入 0 -- 不允许输入
[2]位 -- sex_flag 1--允许输入 0 -- 不允许输入
[3]位 -- score_flag 1--允许输入 0 -- 不允许输入
*/
void GetInfo(struct STUDENT *p,unsigned char flag)
{
if(flag & (1<<0)){
printf("请输入学号:");
scanf("%d",&p->no);
}
if(flag & (1<<1)){
printf("请输入姓名:");
scanf("%s",p->name);
}
if(flag & (1<<2)){
printf("请输入性别:");
getchar();
scanf("%c",&p->sex);
}
if(flag &(1<<3)){
printf("请输入成绩:");
scanf("%f",&p->score);
}
}