链表在几种数据结构中算是比较简单的,操作也比较简单。链表分为单向、双向、循环链表,其中单向链表是所有链表的基础。结合一个简单的例子,用C语 言实践单向链表的创建、修改、删除操作。在实践的过程中,学习了C语言关于scanf的使用技巧:在scanf使用多次时,需要使用 fflush(stdin)来清空缓冲区,最好每次使用后,就刷新一次,以免出现不确定的输入的问题。
学生信息:姓名、年龄。
操作:1、增加;2、修改;3、删除;4、查询;5、退出。其中查询使用strstr()函数,实现部分匹配查找。顺序查询算法复杂度为O(n)。
缺点:只有顺序添加节点功能,没有随机添加节点功能。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAMEMAX 40
#define SUCCESS 1
#define FAIL 0
struct student
{
char studentName[NAMEMAX];
unsigned int studentAge;
struct student* next;
};
typedef struct student node;
typedef struct student* pNode;
static int studentNumber;
/********* 函数声明 开始 *********/
pNode add_student(pNode head);
pNode find_lastNode(pNode head);
void modify_student(pNode head);
pNode delete_student(pNode head);
int search_student(pNode head);
void quit_student(pNode head);
/********* 函数声明 结束 *********/
/***
* 查找最后一个节点
*/
pNode find_lastNode(pNode head)
{
pNode tempPNode;
tempPNode = head;
while(tempPNode->next != NULL)
{
tempPNode = tempPNode->next;
}
return tempPNode;
}
/***
* 显示学生个人信息
*/
void show_student_information(pNode node)
{
printf("姓名:%s\n",node->studentName);
printf("年龄:%u\n",node->studentAge);
}
/**
* 增加学生信息
* 创建单向链表
* head:链表头指针
*/
pNode add_student(pNode head)
{
char tempName[NAMEMAX];//学生姓名临时变量
unsigned int tempAge;//学生年龄临时变量
pNode tempPNode;
pNode tempPPreNode;
char isAdd;
printf("\n************************\n");
printf(" 增加学生信息\n");
printf("************************\n");
printf("请输入学生姓名: ");
scanf("%s",tempName);//输入姓名
printf("请输入学生年龄: ");
while((scanf("%u",&tempAge) !=1) || tempAge <=0)//输入年龄
{
printf("请输入正确的年龄(大于0的整数): ");
}
printf("************************\n");
printf("学生信息\n");
printf("姓名:%s\n", tempName);
printf("年龄:%u\n", tempAge);
printf("是否增加(Y/N): ");
fflush(stdin);//刷新缓冲区
while((scanf("%c",&isAdd) != 1) || (isAdd != 'Y' && isAdd != 'y' && isAdd != 'N' && isAdd != 'n'))//是否增加
{
printf("请输入Y或者y或者N或者n!\n");
printf("是否增加(Y/N): ");
//刷新缓冲区
fflush(stdin);
}
if(isAdd == 'Y' || isAdd == 'y')
{
if(head == NULL)//无节点
{
head = (pNode)malloc(sizeof(node));
strcpy(head->studentName, tempName);
head->studentAge = tempAge;
head->next = NULL;
}
else//有节点
{
tempPNode = (pNode)malloc(sizeof(node));
strcpy(tempPNode->studentName, tempName);
tempPNode->studentAge = tempAge;
tempPNode->next = NULL;
tempPPreNode = find_lastNode(head);
tempPPreNode->next = tempPNode;
}
studentNumber ++;
printf("增加学生信息成功,");
}
else
{
printf("增加学生信息失败,");
}
printf("返回主菜单\n\n");
return head;
}
/**
* 修改学生信息
* 顺序查找链表
*/
void modify_student(pNode head)
{
unsigned int index = 0;//选中学生的序号
unsigned int tmpIndex = 0;//临时变量
pNode tmpNode;//节点临时变量
char tmpName[NAMEMAX];
unsigned int tmpAge = 0;
char isAdd;
if(search_student(head))
{
printf("请选择序号:");
while((scanf("%u",&index) != 1) || index == 0)
{
printf("请输入大于0的整数!\n");
printf("请选择序号:");
fflush(stdin);
}
tmpNode = head;
while(tmpNode)
{
if(strstr(tmpNode->studentName,tmpName) != NULL)/*查找成功*/
{
tmpIndex++;
if(tmpIndex == index)//找到
{
break;
}
else//未找到
{
tmpNode = tmpNode->next;
}
}
}
if(tmpIndex != 0 && tmpIndex == index)//找到
{
printf("选中的学生信息:\n");
show_student_information(tmpNode);
printf("新信息:\n");
printf("姓名:");
scanf("%s",tmpName);
printf("年龄:");
while((scanf("%u",&tmpAge) != 1) || tmpAge == 0)
{
printf("请输入大于0的整数!\n");
printf("年龄:");
fflush(stdin);
}
printf("是否修改(Y/N): ");
fflush(stdin);//刷新缓冲区
while((scanf("%c",&isAdd) != 1) || (isAdd != 'Y' && isAdd != 'y' && isAdd != 'N' && isAdd != 'n'))//是否增加
{
printf("请输入Y或者y或者N或者n!\n");
printf("是否修改(Y/N): ");
//刷新缓冲区
fflush(stdin);
}
if(isAdd == 'Y' || isAdd == 'y')//修改
{
strcpy(tmpNode->studentName, tmpName);
tmpNode->studentAge = tmpAge;
printf("已修改!返回主菜单。\n");
}
else//不修改
{
printf("未修改!返回主菜单。\n");
}
}
else//未找到
{
printf("未修改!返回主菜单。\n");
return;
}
}
}
/***
* 按照姓名模糊查找,并删除相关学生信息
* 删除链表节点
*/
pNode delete_student(pNode head)
{
unsigned int index = 0;//选中学生的序号
unsigned int tmpIndex = 0;//临时变量
pNode tmpNode = NULL;//节点临时变量
pNode tmpPreNode = NULL;//要删除的节点的前一个节点临时变量
char tmpName[NAMEMAX];
char isDel;
if(search_student(head))
{
printf("请选择序号:");
while((scanf("%u",&index) != 1) || index == 0)
{
printf("请输入大于0的整数!\n");
printf("请选择序号:");
fflush(stdin);
}
tmpNode = head;
while(tmpNode)
{
if(strstr(tmpNode->studentName,tmpName) != NULL)/*查找成功*/
{
tmpIndex++;
if(tmpIndex == index)//找到
{
break;
}
else//未找到
{
tmpPreNode = tmpNode;
tmpNode = tmpNode->next;
}
}
}
if(tmpIndex !=0 && tmpIndex == index)//找到
{
printf("是否删除(Y/N): ");
fflush(stdin);//刷新缓冲区
while((scanf("%c",&isDel) != 1) || (isDel != 'Y' && isDel != 'y' && isDel != 'N' && isDel != 'n'))//是否增加
{
printf("请输入Y或者y或者N或者n!\n");
printf("是否删除(Y/N): ");
//刷新缓冲区
fflush(stdin);
}
if(isDel == 'Y' || isDel == 'y')//删除
{
if(tmpNode == head)//如果删除的节点为头结点
{
head = head->next;
}
else if(tmpNode->next != NULL)//删除的节点在中间
{
tmpPreNode->next = tmpNode->next;
tmpNode->next = NULL;
}
else if(tmpNode->next == NULL)//删除的节点在末尾
{
tmpPreNode->next = NULL;
}
free(tmpNode);
tmpNode == NULL;
printf("删除成功!返回主菜单。\n");
studentNumber --;
}
else//不删除
{
printf("未删除!返回主菜单。\n");
}
}
else//未找到
{
printf("未找到!返回主菜单。\n");
}
}
return head;
}
/***
* 按照姓名模糊查找
* 顺序查找链表
*/
int search_student(pNode head)
{
//测试使用
pNode tmpNode;
int tmpIndex = 0;
char tmpName[NAMEMAX];//学生姓名临时变量
if(head == NULL)
{
printf("没有学生信息,请添加!返回主菜单。\n");
return FAIL;
}
printf("\n************************\n");
printf("输入学生姓名【模糊查找】:\n");
fflush(stdin);
scanf("%s",tmpName);
tmpNode = head;
while(tmpNode)
{
if(strstr(tmpNode->studentName,tmpName) != NULL)/*查找成功*/
{
tmpIndex++;
printf("%d:\n",tmpIndex);
show_student_information(tmpNode);
}
tmpNode = tmpNode->next;
}
if(tmpIndex == 0)
{
printf("没有查找到名字中包含%s的学生!\n",tmpName);
printf("\n************************\n");
return FAIL;
}
printf("\n************************\n");
return SUCCESS;
}
/**
* 退出系统,删除所有学生信息
* 删除链表
*/
void quit_student(pNode head)
{
pNode tmpNode1 = NULL;
pNode tmpNode2 = NULL;
if(head == NULL)
{
return;
}
tmpNode1 = head;
while(tmpNode1)
{
tmpNode2 = tmpNode1->next;
free(tmpNode1);
tmpNode1 = tmpNode2;
}
head = NULL;
}
/*****
* 主程序
*/
int main(void)
{
int choice;//用户选项
int isContinue;//是否继续
pNode head;//链表头
choice = 0;
studentNumber = 0;
head = NULL;
isContinue = 1;
do{
printf("************************\n");
printf("欢迎使用学生信息管理系统\n");
printf("************************\n");
printf("主菜单:\n");
printf("1.增加学生信息\n");
printf("2.修改学生信息\n");
printf("3.删除学生信息\n");
printf("4.查询学生信息\n");
printf("5.退出系统\n");
printf("------------------------\n");
printf("已有%d名学生信息\n",studentNumber);
printf("------------------------\n");
printf("请输入菜单选项(1-5): ");
while((scanf("%d",&choice) != 1) || (choice > 5) || (choice < 1))
{
printf("警告:请输入1-5整数!\n");
printf("请输入菜单选项(1-5): ");
fflush(stdin);//刷新缓冲区
}
switch(choice)
{
case 1://增加
head = add_student(head);
break;
case 2://修改
modify_student(head);
break;
case 3://删除
head = delete_student(head);
break;
case 4://查询
search_student(head);
break;
case 5://退出系统
quit_student(head);
isContinue = 2;
break;
default://异常错误,暂无处理
printf("出现异常错误,退出系统!\n");
break;
}
}while(isContinue == 1);
return 0;
}