通讯录是许多手机等电子产品必带功能之一,在有了数据结构中链表的相关知识后,便可以自己制作一个简单的通讯录了。
制作通讯录的一些基础知识
- 结构体
- 结构体是什么?说白了结构体是一种类型,它可以是一些其他类型的集合体;打个比方,数组是它元素类型的集合体,int a[10]是int类型的集合体;同理,结构体是它自身一些元素类型的集合体;为什么说是一些呢?这就涉及到了数组与结构体的区别了;数组中元素的类型是确定,一致的,而在结构体中,其元素可以是不同类型的。
- 本文用到的结构体
//个人信息
struct people
{
char name[20];
int number;
};
- 链表
-
链表是一系列的存储数据元素的单元通过指针串接起来形成的,因此每个单元至少有两个域,一个域用于数据元素的存储,另一个或两个域是指向其他单元的指针。这里具有一个数据域和多个指针域的存储单元通常称为节点(node)。
-
链表的第一个节点和最后一个节点,分别称为链表的头节点和尾节点。尾节点的特征是其 next 引用为空(null)。链表中每个节点的 next 引用都相当于一个指针,指向另一个节点,借助这些 next 引用,我们可以从链表的头节点移动到尾节点
-
本文用到的链表节点
//双向链表节点设计
struct double_list
{
struct double_list *prev; //用于存放上一个(前缀)节点地址指针变量
struct people data; //数据 数据域
struct double_list *next; //用于存放下一个(后缀)节点地址指针变量
};
功能
- 使用链表实现增加(在增加人员的过程中有一个自动排序功能,比如按姓名排序)、删除、修改、查找(比如:工号查找、电话查找)的功能;
- 添加用户信息
- 列出好友信息
- 查找好友信息(按姓名、号码查找)
- 删除好友
- 修改号码
- 退出
代码
链表节点创建
//(2)节点初始化(在堆空间生成节点)
struct double_list *new_node(void)
{
struct double_list *p = NULL; //指针变量p
//在堆空间开辟内存,大小为:sizeof(struct double_list)
p = (struct double_list *)malloc(sizeof(struct double_list));
if(p == NULL)
{
printf("开辟空间失败!\n");
return 0;
}
p->data.number=0;//结构体成员初始化
//两个指针成员存放自己的地址,即单个节点也是循环链表
p->next = p;
p->prev = p;
return p;
}
节点插入 增加节点到链表头
void insert_node(struct double_list *p, struct double_list *new)
{
if(p == NULL || new == NULL)
{
return;
}
new->next = p->next;
p->next->prev = new;
new->prev = p;
p->next = new;
}
节点插入 增加节点到链表尾部
void insert_node_tail(struct double_list *p, struct double_list *new)
{
if(p == NULL || new == NULL)
{
return;
}
p->prev->next = new;
new->prev = p->prev;
p->prev = new;
new->next = p;
}
节点查找(姓名、号码)
struct double_list *find_node(struct double_list *head, struct people s)
{
struct double_list *p;
int ret;
p = head->next; //指针第一个数据节点
while(p != head) //有数据节点
{
ret = strcmp(p->data.name,s.name);
if(ret == 0)
{
return p; //返回节点地址 结束循环
}
p = p->next; //移动到下一个节点
}
//遍历完成整个链表,无法查找与数据相等的节点,返回NULL
return NULL;
}
struct double_list *find_node1(struct double_list *head, struct people s)
{
struct double_list *p;
int ret;
p = head->next; //指针第一个数据节点
while(p != head) //有数据节点
{
if(p->data.number == s.number);
if(ret == 0)
{
return p; //返回节点地址 结束循环
}
p = p->next; //移动到下一个节点
}
//遍历完成整个链表,无法查找与数据相等的节点,返回NULL
return NULL;
}
节点删除
void del_node(struct double_list *del)
{
del->prev->next = del->next;
del->next->prev = del->prev;
del->prev = del;
del->next = del;
}
因为我删除之前进行查找操作,此处代码操作将数据节点解下来,所以我再主函数进行释放节点。
显示节点
//节点显示
void display_node(struct double_list *head)
{
struct double_list *p;
p = head->next; //指针第一个数据节点
while(p != head) //有数据节点
{
printf("名字:%s\t", p->data.name);
printf("电话号码:%d", p->data.number);
printf("\n");
p = p->next;
}
printf("\n");
}
主函数逻辑
printf("\033[1;31;46m=========================通讯录============================ \033[0m\n");
printf("******************* 添加联系人 :1******************\n");
printf("******************* 查看所有 :2******************\n");
printf("******************* 查找联系人(名) :3******************\n");
printf("******************* 查找联系人(号) :4******************\n");
printf("******************* 删除联系人 :5******************\n");
printf("******************* 修改联系方式 :6******************\n");
printf("******************* 退出通讯录 :q******************\n");
printf("\033[1;31;46m=========================================================== \033[0m\n");
此处printf("\033");是更改显示的颜色,不需要可以去除。