目录
目标需求:
虽然只要求1000个人,但是看标题就知道我做的应该是不限制大小的,没错,我不知死活的用了单链表来存,给自己挖了一个坑,但相信我,链表,是可以做的!
一、菜单
一个平平无奇的菜单。
int menu()
{
puts("***************************************************");
puts("********** 通讯录1.0 ***********");
puts("********** ***********");
puts("********** 1.新增 2.删除 3.查找 ***********");
puts("********** 4.修改 5.显示联系人 ***********");
puts("********** 6清空通讯录 7.以名称排序 ***********");
puts("******** 0.退出 *********");
puts("***************************************************");
int i;
scanf("%d", &i);
return i;
}
二、功能0-退出
这是主函数的代码,首先我写了一个枚举类型来进行switch的判断,而退出只需要在选择0的时候直接退出程序就可以了,代码里我只是习惯用flag标记了,这个程序只做一件事,不用标记再退。
enum Choose
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
CLEAN,
SORT
};
int main()
{
int flag = 0;
struct data *head = (struct data *)malloc(sizeof(struct data));
head->next = NULL;
while (1)
{
switch (menu())
{
case EXIT:
flag = 1;
break;
case ADD:
add(head);
break;
case DEL:
del(head);
break;
case SEARCH:
sesrch(head);
break;
case MODIFY:
modify(head);
break;
case SHOW:
show(head);
break;
case CLEAN:
clean(head);
break;
case SORT:
sort(head);
break;
default:
printf("输入错误,请重新输入\n");
break;
};
if (flag)
break;
}
return 0;
}
二、功能1-增加联系人
这里的链表的头节点我没有存数据,后面有大用处,需要注意新节点的next指针指向空指针,这个主要用于判断链表是否到末尾。
还有一个主要从用户角度出发,没有申请到内存的时候要提醒用户并退出
void add(struct data *p)
{
if (p->next)
{ //如果为NULL则不会
while (p->next)
{
p = p->next;
}
}
p->next = (struct data *)malloc(sizeof(struct data));//防止
if (p->next == NULL)
{
printf("内存申请失败,请重试或释放内存\n");
return;
}
p = p->next; //指向最后个空的元素
p->next = NULL;
printf("请输入姓名\n");
scanf("%s", p->name);
printf("再输入输入姓别\n");
scanf("%s", p->sex);
printf("他\\她的年龄\n");
scanf("%hd", &(p->age)); //注意用的short类型
printf("他\\她地址\n");
scanf("%s", p->address);
printf("他\\她的电话\n");
scanf("%s", p->phone);
}
三、功能2-删除
找到要删除的节点后,我们要把节点的上一位next修改为节点的next,由于单链表无法回溯,所以我们只能用两个指针,一个在另一个前面,后面的那个指针用于判断
void del(struct data *p)
{
if (!p->next)
{
printf("通讯录为空\n");
return;
}
printf("请输入你要删除的人的性名\n");
char n[MAX_NAME];
scanf("%s", n);
int i;
struct data *t = p;
while (1)
{
t = p;
p = p->next;
i = 0;
while (p->name[i] == n[i])
{
if (!(p->name[i]) || !(n[i]))
break;
i++;
}
if (p->name[i] == n[i])
{
t->next = p->next;
free(p);
return;
}
if (p->next == NULL)
break;
}
printf("查无此人\n");
}
四、功能3-查找
查找到之后如果使用左对齐可以更好的表现出表格效果哦!
void sesrch(struct data *p)
{
if (!p->next)
{
printf("通讯录为空\n");
return;
}
printf("请输入你要查询的人的性名\n");
char n[MAX_NAME];
scanf("%s", n);
int i;
struct data *t = p;
while (1)
{
t = p;
p = p->next;
i = 0;
while (p->name[i] == n[i])
{
if (!(p->name[i]) || !(n[i]))
break;
i++;
}
if (p->name[i] == n[i])
{
printf("姓名 姓别 年龄 地址 电话\n");
printf("%-14s%-13s%-13hd%-12s%s\n", p->name, p->sex, (p->age), p->address, p->phone);
return;
}
if (p->next == NULL)
break;
}
printf("查无此人\n");
}
五、功能4-修改
查找之后多了个功能,不用说了吧
void modify(struct data *p)
{
if (!p->next)
{
printf("通讯录为空\n");
return;
}
printf("请输入你要修改的人的性名\n");
char n[MAX_NAME];
scanf("%s", n);
int i, j;
struct data *t = p;
while (1)
{
t = p;
p = p->next;
i = 0;
while (p->name[i] == n[i])
{
if (!(p->name[i]) || !(n[i]))
break;
i++;
}
if (p->name[i] == n[i])
{
while (1)
{
printf("请输入你要修改哪一项\n1.姓名 2.姓别 3.年龄 4.地址 5.电话 0.修改完毕\n");
scanf("%d", &j);
switch (j)
{
case EXIT:
return;
break;
case 1:
printf("请修改后的姓名\n");
scanf("%s", p->name);
break;
case 2:
printf("请修改后的姓别\n");
scanf("%s", p->sex);
break;
case 3:
printf("请修改后的年龄\n");
scanf("%hd", &(p->age));
break;
case 4:
printf("请修改后的地址\n");
scanf("%s", p->address);
break;
case 5:
printf("请修改后的电话\n");
scanf("%s", p->phone);
break;
default:
printf("输入错误,请重新输入\n");
break;
};
}
return;
}
if (p->next == NULL)
break;
}
printf("查无此人\n");
}
六、功能5-显示联系人
同样运用了左对齐
void show(struct data *p)
{
printf("姓名 姓别 年龄 地址 电话\n");
while (p->next)
{
p = p->next;
printf("%-14s%-13s%-13hd%-12s%s\n", p->name, p->sex, (p->age), p->address, p->phone);
}
}
七、功能6-清空通讯录
删除节点就行了,记得释放空间
void clean(struct data *p)
{
struct data *t = p->next;
p->next = NULL;
if (t)
p = t->next;
else
{
printf("通讯录为空\n");
return;
}
while (1)
{
free(t);
t = p;
if (p)
p = p->next;
else
break;
}
free(p);
return;
}
八、功能7-以名称排序
重点来了,敲黑板!
这里我对整个结构体进行了排序,首先我们可以写一个交换结构体节点的交换函数。
void E(struct data *p1, struct data *p2, struct data *h)
{
struct data *t1 = h, *t2 = h;
while (t1->next != p1)
{
t1 = t1->next;
}
while (t2->next != p2)
{
t2 = t1->next;
}
t1->next = p2;
t2->next = p1;
t1 = p1->next;
p1->next = p2->next;
p2->next = t1;
}
排序方法我用的冒泡排序,因为用到结构体上比较简单。
因为链表的大小我们不知道,所以我们要在函数内计算大小,
为什么我在交换的时候要用两个指针暂存然后先前往下一位呢呢?因为交换了元素之后节点向下移动就不会是原来的下一个了,
平常我们的交换元素就像交换火车车厢里的人,这里的交换就是直接交换车厢。
void sort(struct data *p)
{
if (!(p->next && (p->next)->next))
{
printf("目前不需要排序\n");
return;
}
struct data *t1 = p, *t2;
int count = 0;
while (t1)
{
t1 = t1->next;
count++;
}
count--;
struct data *a,*b;
int i, j;
for (i = 0; i < count - 1; i++)
{
t1 = p->next;
t2 = t1->next;
for (j = 0; j < count - i - 1; j++)
{
a=t1,b=t2;
t1 = t1->next;
t2 = t2->next;
if (strcmp(a->name, b->name) > 0)
E(a, b, p);
}
}
}
完整代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME 24
#define SEX 14
#define MAX_AD 100
#define MAX_PHONE 24
struct data
{
char name[MAX_NAME];
char sex[SEX];
short age; // hd 岁数最多一百多吧
char address[MAX_AD];
char phone[MAX_PHONE];
struct data *next;
};
enum Choose
{
EXIT,
ADD,
DEL,
SEARCH,
MODIFY,
SHOW,
CLEAN,
SORT
};
int menu();
void add(struct data *p);
void show(struct data *p);
void del(struct data *p);
void sesrch(struct data *p);
void modify(struct data *p);
void clean(struct data *p);
void sort(struct data *p);
void E(struct data *p1, struct data *p2, struct data *h);//链表节点的交换
int main()
{
int flag = 0;
struct data *head = (struct data *)malloc(sizeof(struct data));
head->next = NULL;
while (1)
{
switch (menu())
{
case EXIT:
flag = 1;
break;
case ADD:
add(head);
break;
case DEL:
del(head);
break;
case SEARCH:
sesrch(head);
break;
case MODIFY:
modify(head);
break;
case SHOW:
show(head);
break;
case CLEAN:
clean(head);
break;
case SORT:
sort(head);
break;
default:
printf("输入错误,请重新输入\n");
break;
};
if (flag)
break;
}
return 0;
}
int menu()
{
puts("***************************************************");
puts("********** 通讯录1.0 ***********");
puts("********** ***********");
puts("********** 1.新增 2.删除 3.查找 ***********");
puts("********** 4.修改 5.显示联系人 ***********");
puts("********** 6清空通讯录 7.以名称排序 ***********");
puts("******** 0.退出 *********");
puts("***************************************************");
int i;
scanf("%d", &i);
return i;
}
void add(struct data *p)
{
if (p->next)
{ //如果为NULL则不会
while (p->next)
{
p = p->next;
}
}
p->next = (struct data *)malloc(sizeof(struct data));//防止
if (p->next == NULL)
{
printf("内存申请失败,请重试或释放内存\n");
return;
}
p = p->next; //指向最后个空的元素
p->next = NULL;
printf("请输入姓名\n");
scanf("%s", p->name);
printf("再输入输入姓别\n");
scanf("%s", p->sex);
printf("他\\她的年龄\n");
scanf("%hd", &(p->age)); //注意用的short类型
printf("他\\她地址\n");
scanf("%s", p->address);
printf("他\\她的电话\n");
scanf("%s", p->phone);
}
void show(struct data *p)
{
printf("姓名 姓别 年龄 地址 电话\n");
while (p->next)
{
p = p->next;
printf("%-14s%-13s%-13hd%-12s%s\n", p->name, p->sex, (p->age), p->address, p->phone);
}
}
void del(struct data *p)
{
if (!p->next)
{
printf("通讯录为空\n");
return;
}
printf("请输入你要删除的人的性名\n");
char n[MAX_NAME];
scanf("%s", n);
int i;
struct data *t = p;
while (1)
{
t = p;
p = p->next;
i = 0;
while (p->name[i] == n[i])
{
if (!(p->name[i]) || !(n[i]))
break;
i++;
}
if (p->name[i] == n[i])
{
t->next = p->next;
free(p);
return;
}
if (p->next == NULL)
break;
}
printf("查无此人\n");
}
void sesrch(struct data *p)
{
if (!p->next)
{
printf("通讯录为空\n");
return;
}
printf("请输入你要查询的人的性名\n");
char n[MAX_NAME];
scanf("%s", n);
int i;
struct data *t = p;
while (1)
{
t = p;
p = p->next;
i = 0;
while (p->name[i] == n[i])
{
if (!(p->name[i]) || !(n[i]))
break;
i++;
}
if (p->name[i] == n[i])
{
printf("姓名 姓别 年龄 地址 电话\n");
printf("%-14s%-13s%-13hd%-12s%s\n", p->name, p->sex, (p->age), p->address, p->phone);
return;
}
if (p->next == NULL)
break;
}
printf("查无此人\n");
}
void modify(struct data *p)
{
if (!p->next)
{
printf("通讯录为空\n");
return;
}
printf("请输入你要修改的人的性名\n");
char n[MAX_NAME];
scanf("%s", n);
int i, j;
struct data *t = p;
while (1)
{
t = p;
p = p->next;
i = 0;
while (p->name[i] == n[i])
{
if (!(p->name[i]) || !(n[i]))
break;
i++;
}
if (p->name[i] == n[i])
{
while (1)
{
printf("请输入你要修改哪一项\n1.姓名 2.姓别 3.年龄 4.地址 5.电话 0.修改完毕\n");
scanf("%d", &j);
switch (j)
{
case EXIT:
return;
break;
case 1:
printf("请修改后的姓名\n");
scanf("%s", p->name);
break;
case 2:
printf("请修改后的姓别\n");
scanf("%s", p->sex);
break;
case 3:
printf("请修改后的年龄\n");
scanf("%hd", &(p->age));
break;
case 4:
printf("请修改后的地址\n");
scanf("%s", p->address);
break;
case 5:
printf("请修改后的电话\n");
scanf("%s", p->phone);
break;
default:
printf("输入错误,请重新输入\n");
break;
};
}
return;
}
if (p->next == NULL)
break;
}
printf("查无此人\n");
}
void clean(struct data *p)
{
struct data *t = p->next;
p->next = NULL;
if (t)
p = t->next;
else
{
printf("通讯录为空\n");
return;
}
while (1)
{
free(t);
t = p;
if (p)
p = p->next;
else
break;
}
free(p);
return;
}
void sort(struct data *p)
{
if (!(p->next && (p->next)->next))
{
printf("目前不需要排序\n");
return;
}
struct data *t1 = p, *t2;
int count = 0;
while (t1)
{
t1 = t1->next;
count++;
}
count--;
struct data *a,*b;
int i, j;
for (i = 0; i < count - 1; i++)
{
t1 = p->next;
t2 = t1->next;
for (j = 0; j < count - i - 1; j++)
{
a=t1,b=t2;
t1 = t1->next;
t2 = t2->next;
if (strcmp(a->name, b->name) > 0)
E(a, b, p);
}
}
}
void E(struct data *p1, struct data *p2, struct data *h)
{
struct data *t1 = h, *t2 = h;
while (t1->next != p1)
{
t1 = t1->next;
}
while (t2->next != p2)
{
t2 = t1->next;
}
t1->next = p2;
t2->next = p1;
t1 = p1->next;
p1->next = p2->next;
p2->next = t1;
}