完成了链表的学习,我们可以尝试写一些小的案例练习链表的操作。
下面我来为大家介绍用单链表实现一个简单的电话本程序。
首先我们分析一下一个完整的电话本应该包含以下功能:
1.添加联系人
2.删除联系人
3.修改联系人
4.查找联系人
5.查看所有联系人
6.清空联系人
而修改练习人又可能包含以下选项:
(1)修改姓名
(2)修改性别
(3)修改年龄
(4)修改电话号码
(5)修改地址
分析到这儿,我们就可以着手写代码了。
头文件:
//book.h
#pragma
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#define TestType printf("\n################################# %s #############################\n",__FUNCTION__)
typedef struct BookNode{
char name[20];
char gender[8];
int age;
char telephone[20];
char address[100];
struct BookNode* next;
} BookNode;
//初始化电话本
void BookListInit(BookNode** phead);
//打印电话本
void BookListPrint(BookNode* head, const char* msg);
//插入联系人
void BookListInsert(BookNode** phead,char* name,char* gender,int age,char* telephone,char* address);
//寻找联系人的位置
BookNode* BookListFindPos(BookNode* phead, char* to_find);
//删除联系人
void BookListErase(BookNode** phead, char* to_delete);
//查找联系人
void BookListFind(BookNode* phead, char* to_find);
//销毁电话本
void BookListDestroy(BookNode** phead);
//更改联系人信息
void BookListChange(BookNode** phead, char* to_change, int flag, char* newmsg);
//菜单
void TelephoneBookMenu();
具体实现
#include"book.h"
void BookListInit(BookNode** phead){
if(phead == NULL){
return;
}
*phead = NULL;
}
void Destroynode(BookNode* node){
free(node);
}
//创建一个新的联系人节点
BookNode* CreateMum(char* uname,char* ugender,int uage,char* utelephone,char* uaddress){
BookNode* new_node = (BookNode*)malloc(sizeof(BookNode));
if(new_node == NULL){
//申请内存失败
return NULL;
}
//存入将练习人信息保存到节点中
strcpy(new_node->name,uname);
strcpy(new_node->gender,ugender);
new_node->age = uage;
strcpy(new_node->telephone,utelephone);
strcpy(new_node->address,uaddress);
new_node->next = NULL;
return new_node;
}
//打印电话本
void BookListPrint(BookNode* head, const char* msg){
printf("[ %s ]:\n", msg);
BookNode* cur = head;
if(cur == NULL){
printf("电话簿为空!\n");
return;
}
for(;cur != NULL;cur = cur->next){
printf("name:[ %s ]\ngender:[ %s ]\nage:[ %d ]\ntelephone:[ %s ]\naddress:[ %s ]\n\n",cur->name,cur->gender,cur->age,cur->telephone,cur->address);
}
return;
}
//将联系人信息插入链表中
void BookListInsert(BookNode** phead,char* name,char* gender,int age,char* telephone,char* address){
if(phead == NULL){
//非法输入
return;
}
if(*phead == NULL){
//空链表,直接将新节点插入链表
*phead = CreateMum(name,gender,age,telephone,address);
return;
}
BookNode* cur = *phead;
while(cur->next != NULL){
cur = cur->next;
}
//不是空链表,找到最后一个节点,将新节点查到该节点之后
cur->next = CreateMum(name,gender,age,telephone,address);
return;
}
BookNode* BookListFindPos(BookNode* phead, char* to_find){
if(phead == NULL){
return NULL;
}
BookNode* cur = phead;
while(cur != NULL){
if(!strcmp(cur->name,to_find)){
return cur;
}
cur = cur->next;
}
return NULL;
}
//删除联系人节点
void BookListErase(BookNode** phead, char* to_delete){
if(phead == NULL){
//非法输入
return;
}
if(*phead == NULL){
//空链表
return;
}
BookNode* pos = BookListFindPos(*phead,to_delete);
if(pos == NULL){
return;
}
if( pos->next != NULL){
strcpy((pos->name),(pos->next->name));
strcpy((pos->gender),(pos->next->gender));
strcpy((pos->telephone),(pos->next->telephone));
strcpy((pos->address),(pos->next->address));
pos->age = pos->next->age;
BookNode* cur = pos->next;
pos->next = pos->next->next;
Destroynode(cur);
cur = NULL;
return;
}
if(pos->next == NULL){
BookNode* cur = *phead;
while(cur->next != pos){
cur = cur->next;
}
Destroynode(pos);
cur->next = NULL;
return;
}
}
//查找联系人,并打印具体信息
void BookListFind(BookNode* phead, char* to_find){
if(phead == NULL){
//空链表
return;
}
BookNode* cur = phead;
while(cur != NULL){
if(!strcmp((cur->name),to_find)){
printf("name:[ %s ]\ngender:[ %s ]\nage:[ %d ]\ntelephone:[ %s ]\naddress:[ %s ]\n\n",cur->name,cur->gender,cur->age,cur->telephone,cur->address);
return;
}
cur = cur->next;
}
printf("[ 抱歉,没有找到联系人! ]\n");
return;
}
void BookListDestroy(BookNode** phead){
if(phead == NULL){
return;
}
if(*phead == NULL){
printf("[ 电话本为空,无法删除! ]\n");
return;
}
while((*phead)!= NULL){
BookNode* cur = *phead;
Destroynode(cur);
(*phead) = (*phead)->next;
}
return;
}
void BookListChange(BookNode** phead,char* to_change,int flag,char* newmsg){
if(phead == NULL){
return;
}
if(*phead == NULL){
return;
}
BookNode* pos = BookListFindPos(*phead, to_change);
if(pos == NULL){
return;
}
switch(flag){
case 1:
//因为输入的是字符串,所以我们用atoi函数将字符串转换为整型
strcpy((pos->name),newmsg);
break;
case 2:
pos->age = atoi(newmsg);
break;
case 3:
strcpy(pos->telephone,newmsg);
break;
case 4:
strcpy(pos->address,newmsg);
break;
}
return;
}
void TelephoneBookMenu(){
printf("************************************************************\n");
printf("******************* 大凯凯的电话本 ***************************\n");
printf("************************************************************\n");
printf("****** 1.添加联系人 ************* 2.删除联系人 *************\n");
printf("************************************************************\n");
printf("****** 3.修改联系人 ************* 4.查找联系人 *************\n");
printf("************************************************************\n");
printf("****** 5.查看所有联系人 ********* 6.清空所有联系人 *********\n");
printf("************************************************************\n");
printf("********************************************* 0.退出 *******\n");
printf("************************************************************\n");
}
接下来是主函数:
int main(){
BookNode* phead;
BookListInit(&phead);
char uname[20];
char ugender[8];
int uage;
char utelephone[20];
char uaddress[100];
while(1){
int choose = 0;
TelephoneBookMenu();
printf("请选择:");
scanf("%d",&choose);
switch(choose){
case 0:
exit(1);
case 1:
{
printf("请输入姓名:\n");
scanf("%s",uname);
printf("请输入性别:\n");
scanf("%s",ugender);
printf("请输入年龄:\n");
scanf("%d",&uage);
printf("请输入电话号:\n");
scanf("%s",utelephone);
printf("请输入地址:\n");
scanf("%s",uaddress);
BookListInsert(&phead,uname,ugender,uage,utelephone,uaddress);
}
break;
case 2:
{
printf("请输入删除联系人姓名:\n");
scanf("%s",uname);
BookListErase(&phead,uname);
}break;
case 3:
{
int choose2 = 0;
char newmsg[100];
printf("请输入修改联系人姓名\n");
scanf("%s",uname);
printf("#############################################################\n");
printf("#########1.修改姓名 ##############2.修改年龄#################\n");
printf("#############################################################\n");
printf("#########3.修改电话号码###########4.修改地址#################\n");
printf("#############################################################\n");
printf("请选择:");
scanf("%d",&choose2);
printf("请输入修改信息:\n");
scanf("%s",newmsg);
BookListChange(&phead,uname,choose2,newmsg);
}break;
case 4:
{
printf("请输入查找联系人姓名:\n");
scanf("%s",uname);
BookListFind(phead,uname);
}break;
case 5:
{
BookListPrint(phead,"联系人信息");
}break;
case 6:
{
BookListDestroy(&phead);
}break;
}
}
}
双手奉上,Makefile.
telephone_book:book.c main.c
gcc -g $^ -o $@
.PHONY:clean
clean:
rm telephone_book
大功告成!
最后,还有一些小建议,为了便于程序的调试,我们最好在每个函数完成之后,都单独写一个测试函数,例如:
//BookListInsert的测试函数
TestBookListInsert(){
TestType;
BookNode* phead;
BookListInit(&phead);
BookListInsert(&phead,"凯凯","男",22,"1778279xxxx","陕西科技大学六公寓");
BookListPrint(phead,"打印信息");
BookListInsert(&phead,"晨佩","女",21,"1829200xxxx","陕西科技大学四公寓");
BookListInsert(&phead,"赵某某","女",21,"1559184xxxx","陕西科技大学九公寓");
BookListPrint(phead,"打印信息");
}
int main(){
TestBookListInsert();
return 0;
}
这样可以极大程度的减少我们在后期调试的复杂度。
这是我自己胡乱琢磨的一个小案例,如果有什么bug或者不妥之处,欢迎发邮件到我的邮箱 ( Cyrus_wen@163.com ) 批评指正。