C语言单链表编写电话簿
这次利用单链表做了一个简单的电话簿
这是程序中用到的头文件:
#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"malloc.h"
#include"ctype.h"
首先在这里定义了一个结构体,这个结构体包含两部分 ,一个是指针域,另一个是数据域,数据域也是一个结构体,里面包含了联系人的姓名和电话号码。
typedef char DataType;
typedef struct Node{//定义
struct {
char name[20];
char number[12];
}data;
char name[20];
char number[12];
struct Node *next;
}LNode,*LinkList;
这里首先定义了一个头结点,这个是全局变量,这样定义就不用在各个函数之间来回传参数了,头结点的内存空间已经在主函数内申请了,所以下面可以直接使用
LinkList L;
首先,链表的插入方法有两种一种是头插法,一种是尾插法,不懂得小伙伴可以百度去查一下,这里就不进行过多的介绍了。
两种插入方法这里都有,大家可以自由选择。下面这一部分用的是头插法,简单来说就是先存入的在后面。大家可以自己试一下。
void CreateLinkList(){//头插
LNode *s;
DataType x=1;
while(x!=2){
s=(LinkList)malloc(sizeof(LNode));
printf("请输入联系人姓名:");
scanf("%s",s->data.name);
printf("请输入联系人电话号码:");
CheckLinkList();
s->next=L->next;
L->next=s;
printf("添加成功!是否继续新建联系人?\t");
printf("1.是 2.否\n");
scanf ("%d",&x);
}
printf("头插法插入已完成!\n");
printf("请选择你的操作:");
}
这里是尾插法,与头插法的区别就是先插入的在前面。
void CreateLinkList2(){//尾插
LNode *r,*s;
int x=1;
r=L;
while(x!=2){
s=(LinkList)malloc(sizeof(LNode));
printf("请输入联系人姓名:");
scanf("%s",s->data.name);
printf("请输入联系人电话号码:");
CheckLinkList();
r->next=s;
r=s;
printf("添加成功!是否继续新建联系人?\t");
printf("1.是 2.否\n");
scanf ("%d",&x);
}
r->next=NULL;
printf("尾插法插入已完成!\n");
printf("请选择你的操作:");
}
输入需要查找的内容进行查找,内容包括姓名和电话,两者选择一种都可以。
找到后返回找到的该结点,如果没有找到就返回尾节点。
LNode *LocationLinkList(){//按值查找
LNode *p;
int len;
DataType x;
char message[20];
p=L->next;
printf("请输入要查找的信息:");
scanf("%s",message);
if(!isdigit(message[0])){ //通过姓名查找
loop: while(p!=NULL){
if(strcmp(message,p->data.name)==0){
return p;
}
else
p=p->next;
}
return p;
}
else {//通过号码查找查找
if(strlen(message)!=11)
goto loop;
while(p!=NULL){
if(strcmp(message,p->data.number)==0){
return p;
}
p=p->next;
}
return p;
}
}
输入需要查找的位置,也就是序号进行查找。找到后返回找到的结点,如果没有找到就返回尾节点。
LNode *GetLinkList(int i){//按序号查找
LNode *p;
int j;
p=L;
j=0;
while((p!=NULL)&&(i>j)){
p=p->next;
j++;
}
return p;
}
在链表中第i个位置插入新结点,需要先找到需要插入的位置再插入。这里用的是按号查找,只需要找到对应位置插入即可,当然也可以使用按内容查找,如在某人前插入,或者在某人后插入都可以。但是不建议大家用按内容查找因为比较繁琐麻烦。
void InsertLinkList(){//插入
LNode *p,*s;
int i;
DataType x;
printf("请输入需要插入的位置:");
scanf("%d",&i);
p=GetLinkList(i-1);
if(p==NULL){
printf("插入位置不合法!");
exit (1);
}
else{
s=(LinkList)malloc(sizeof(LNode));
printf("请输入需要插入的联系人姓名:");
scanf("%s",s->data.name);
printf("请输入需要插入的联系人电话:");
CheckLinkList();
s->next=p->next;
p->next=s;
}
printf("添加成功!");
printf("请选择你的操作:");
}
,需要删除某一内容就需要先找到这个家电。这里可以对查找方式进行选择。不论查找方法是什么,最后都是将找到的这个结点返回,查找过程对该结点的前后结点没有影响。
还有要强调的是要释放已删除结点的空间,毕竟电脑内存是有限的,总是将内存分配出去不释放早晚有一天会用完的。
void DeleteLinkList(){//删除第i个结点
LNode *p,*q;
int i;
p=SelectFind();
if(p==NULL||p->next==NULL){//第i个结点的前驱不存在
printf("删除不合法位置!");
exit(1);
}
else{
q=p->next;
p->next=p->next->next;
free(q);
}
printf("删除完成!\n");
printf("请选择你的操作:");
}
这里是求表长,一个简单的计数器。其实也可以在定义结构体时添加一个llength。每新建一个联系人length++,删除一个联系人就length–。也是可以的。这里是把求长度的方法单独写出来了。
int LengthLinkList(){//求表长
int len;
LNode *p;
p=L;
len=0;
while (p->next){
len++;
p=p->next;
}
return len;
}
一个简单的倒序,就比如原先顺序是123456,经过倒序后变成654321。
void ReverseLinkList(){//逆置
LNode *p,*q;
p=L->next;
L->next=NULL;
while(p){
q=p;
p=p->next;
q->next=L->next;
L->next=q;
}
printf("逆置完成!\n");
printf("请选择你的操作:");
}
修改链表(电话簿)中的内容,这里可以可以对查找方式进行选择。
void ChargeLinkLIst (){//修改
int i,len;
LNode *s;
len=LengthLinkList();
printf("请输入要修改的位置:");
loop: scanf("%d",&i);
if(i>len|| i<0)
{
printf("此位置暂无联系人,无法修改,请重新输入:");
goto loop;
}
s=SelectFind();
printf("请输入更改后的名字:");
scanf("%s",s->data.name);
printf("请输入更改后的号码:");
CheckLinkList();
printf("修改完成!");
printf("请选择你的操作:");
}
简单的按链表的顺序将每一个结点中的内容都打印出来。
void PrintLinkList(){//打印
LNode *p;
p=L;
printf("姓名\t\t电话\n\n");
while(p->next!=NULL){
p=p->next;
printf("%s\t%s\n",p->data.name,p->data.number);
}
printf("打印完成:");
printf("请选择你的操作:");
}
主菜单方便用户操作,选择。
void menuLinkList(){//主菜单
printf(" 电话簿\n");
printf("------------------------------------------------------------------\n");
printf(" 菜单选项:\n");
printf(" 1 --------------------------------------- 头插法新建电话簿\n");
printf(" 2 --------------------------------------- 尾插法新建电话簿\n");
printf(" 3 --------------------------------------- 插入\n");
printf(" 4 --------------------------------------- 删除\n");
printf(" 5 --------------------------------------- 查找\n");
printf(" 6 --------------------------------------- 修改\n");
printf(" 7 --------------------------------------- 计数\n");
printf(" 8 --------------------------------------- 逆置\n");
printf(" 9 --------------------------------------- 输出\n");
printf(" 10 --------------------------------------- 清屏\n");
printf(" 11 --------------------------------------- 退出\n\n");
printf("------------------------------------------------------------------\n");
printf("请选择您需要的操作:");
}
选择查找方式,包含了按内容查找和按序号查找。
LNode *SelectFind(){//选择查找方式
LNode *p;
int i=0,j;
printf("请选择您需要查找的方式:\n");
printf("1.按序号查找 2.按内容查找\n");
printf("您的选择是:");
while((i!=1)&&(i!=2)){
scanf("%d",&i);
switch(i){
case 1:
printf("请输入需要查找的位置:");
scanf("%d",&j);
p=GetLinkList(j);
break;
case 2:
p=LocationLinkList();
break;
default:
printf("输入有误,请重新输入:");
break;
}
}
return p;
}
检查输入数据是否为11位整数的电话号码
void CheckLinkList(){
LNode *s;
while(1){
int j;
scanf("%s",s->data.number);
if(strlen(s->data.number)==11)
{
for(j=0;j<strlen(s->data.number);j++)
if(!isdigit(s->data.number[j]))//判断是否在0-9之间
break;
if(j==strlen(s->data.number))
break;
}
if(strlen(s->data.number)!=11 || j!= strlen(s->data.number))
printf("输入有误,请重新输入号码:");
}
}
主函数,对各个函数进行调用。
int main (){
int n,i,length;
LNode *p,*s,*q;
L=(LinkList)malloc(sizeof(LNode));
L->next=NULL;
menuLinkList();
while(scanf("%d",&n))
switch(n){
case 1:
CreateLinkList();
break;
case 2:
CreateLinkList2();
break;
case 3:
InsertLinkList();
break;
case 4:
DeleteLinkList();
break;
case 5:
p=SelectFind();
if(p==NULL)
printf("未找到此联系人!");
else{
printf("该联系人已找到.....!\n");
printf("%s\t%s\n",p->data.name,p->data.number);
}
printf("请选择你的操作:");
break;
case 6:
ChargeLinkLIst();
break;
case 7:
length=LengthLinkList();
printf("此电话簿联系人个数为:");
printf("%d",length);
printf("请选择你的操作:");
break;
case 8:
ReverseLinkList();
break;
case 9:
PrintLinkList();
break;
case 10:
system("CLS");
printf("清屏完成");
menuLinkList();
break;
case 11:
exit(1);
default: printf("输入有误,请重新输入:");
break;
}
return 0;
}