鏈表在幾種數據結構中算是比較簡單的,操作也比較簡單。鏈表分爲單向、雙向、循環鏈表,其中單向鏈表是所有鏈表的基礎。結合一個簡單的例子,用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;
}