数据结构:用顺序表和单链表实现通讯录(下)

前言:

上篇主要是用顺序表实现通讯录,本篇主要是用单链表实现通讯录。

分析:

单链表在这里是指单向不带头不循环链表。

如下图所示,通讯录是一个结构体,里面存有数据和下一个结点的地址。数据在这里是联系人信息的结构体。(当然也可以不建两个结构体,只建一个通讯录结构体)

数据结构:用顺序表和单链表实现通讯录(下)_第1张图片

联系人信息   有名字、性别、年龄、电话和地址。姓名性别年龄地址都是数组,因为它们可能用到汉字,汉字是宽字符,一个汉字占两个字节。而char类型的变量只占一个字节。这是不够的。年龄一个整型就足够了,不必要给数组。

数组的长度可以用宏定义,比较方便,也防止在后面再次用的时候记错数字。

建立三个文件,slcontact.h,slcontact.c,test.c。分别用来(主要是)声明函数,定义函数和测试功能等。

slcontact.h:

1.创建联系人结构体和通讯录结构体

2.声明通讯录想要实现的五个功能,封装成五个函数。

3.声明菜单。

4.声明初始化和销毁通讯录。

说明:给函数传的参数,形参用一级指针还是二级指针接收?这个取决于是否要改变当前所传的指针的地址。如果要改变当前指针的地址,就用二级指针接收,如果不需要改变,就可以用一级指针接收。

有时为了保持接口一致性,可以全部都用二级指针(接口中存在二级指针)。

头文件中声明的函数,是测试文件中需要调用的函数。如果测试文件中不需要调用,但在函数实现中需要用到,可以写在函数定义的slcontact.c文件(亦即可以不声明)。比如下面的Addlistback函数。

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#pragma once  //防止头文件被重复引用
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 11
#define ADDR_MAX 100
#include 
#include 
#include 
#include 


//创建联系人结构体
typedef struct PersonInfo
{
    char name[NAME_MAX];
    char sex[SEX_MAX];
    int age;
    char tel[TEL_MAX];
    char addr[ADDR_MAX];
}PeoInfo;//把这个结构体重命名为PeoInfo

//创建一个通讯录,这个通讯录是一个链表
typedef struct contact
{
	//这个链表包含联系人数据和下一个结点的数据
    PeoInfo info;//联系人数据是一个结构体
    struct contact* next;//下一个结点的数据是一个通讯录指针,指针名字是next,储存的是下一个联系人的数据。

}contact;//把这个通讯录结构体重命名为contact



//写下待会要完成的内容,进行声明,然后在slcontact.c文件里实现,在test.c文件里测试

//声明一下菜单
void Menu();

//创建新结点
contact* BuyNode();

//初始化通讯录
void InitContact(contact** con);

//尾插的函数
void Addlistback(contact** con, contact* newnode);
//添加通讯录数据
void AddContact(contact** con);

//删除通讯录数据
void DelContact(contact** con);
//展示通讯录数据
void ShowContact(contact* con);
//查找通讯录数据
void FindContact(contact* con);
//修改通讯录数据
void ModifyContact(contact** con);
//销毁通讯录数据
void DestroyContact(contact** con);

slcontact.c:

实现这些通讯录函数有一些细节需要注意。

包含头文件。

添加联系人时,需要一个创建新结点的函数以及一个尾插的函数。

删除联系人时,需要查找联系人(也可以封装一个函数),找到以后再删除,删除完了再展示一下当前通讯录(这一点可不写)

销毁通讯录时,要写一个循环,逐个释放每一个结点的内存。

实现打印的内容时,格式可以自己调。

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include "slcontact.h"

void Menu()
{
	printf("\n");
	printf("**************通讯录***************\n");
	printf("****1.添加联系人****2.删除联系人***\n");
	printf("****3.查看联系人****4.展示通讯录***\n");
	printf("****5.修改联系人****0.退出通讯录***\n");
	printf("***********************************\n");
	printf("\n\n");
}


//创建新结点
contact* BuyNode()
{
	contact* newnode = (contact*)malloc(sizeof(contact));
	if (newnode == NULL)
	{
		assert("malloc failed");
		exit(1);
	}

	newnode->next = NULL;
	strcpy(newnode->info.name, " ");
	
	return newnode;
}

//初始化通讯录
void InitContact(contact** con)//头指针是*con
{
	assert(con);
	*con = NULL;
}

//添加通讯录数据之前要有一个尾插的函数
//尾插

void Addlistback(contact** con,contact* newnode)
{
	assert(con);
	contact* pcur = *con;//创建一个新的指针指向头结点
	if (pcur == NULL)
	{
		*con = newnode;
	}
	else
	{
		while (pcur->next != NULL)//找尾结点
		{
			pcur = pcur->next;
		}
		pcur->next = newnode;//找到以后把这个新结点放在尾结点的下一个结点,实现尾插
	}
	
}
//添加联系人
void AddContact(contact** con)
{
	assert(con);
	contact* newnode = BuyNode();//创建联系人结构体,把数据存在临时的联系人中
	printf("请输入您要添加的联系人姓名:\n");
	scanf("%s", newnode->info.name);//数组名就是首元素地址,name是数组名
	printf("请输入您要添加的联系人性别:\n");
	scanf("%s", newnode->info.sex);
	printf("请输入您要添加的联系人年龄:\n");
	scanf("%d", &newnode->info.age);//这里要取地址,因为age不是数组
	printf("请输入您要添加的联系人电话:\n");
	scanf("%s", newnode->info.tel);
	printf("请输入您要添加的联系人地址:\n");
	scanf("%s", newnode->info.addr);


	Addlistback(con,newnode);//把头指针的指针和临时信息传过去
	printf("联系人添加成功!\n");
	ShowContact(*con);
}

//删除通讯录数据之前要查找联系人
void DelContact(contact** con)
{
	assert(con);
	assert(*con);
	printf("请输入您要删除的联系人:\n");

	char name[NAME_MAX];
	scanf("%s",name);
	contact* del = *con;
	contact* prev = NULL;
	while (del != NULL && strcmp(del->info.name, name) != 0)//这个指针有数,且不是我要删的数
	{
	/*	del = del->next;
		prev = del;(顺序不能乱!!!!!)*/
		prev = del;
		del = del->next;
	}
	if (del == NULL)//跳出循环后,del还是空,说明不存在
	{
		printf("您要删除的联系人不存在!\n");
		return;//(这里不存在以后,要及时return,不能再继续后面的操作了,不然会出错!!!!!
	}
	else if (prev == NULL)//del!=NULL,但是第一次就没进入循环因为第一个数就是del
	{
		*con = (*con)->next;
	}
	else//del!=NULL,del是除第一个数之外的其他数
	{
		prev->next = del->next;
	}
	    free(del);
	    del = NULL;
		printf("联系人删除成功!\n");
		ShowContact(*con);
}


//展示通讯录数据
void ShowContact(contact* con)
{
	if (con == NULL)
	{
		return;
	}
	printf("%-4s %-4s %-4s %-4s %-4s\n", "姓名", "性别", "年龄", "电话", "地址" );
	contact* pcur = con;
	while (pcur)
	{
		printf("%-4s ", pcur->info.name);
		printf("%-4s ", pcur->info.sex);
		printf("%-4d ", pcur->info.age);
		printf("%-4s ", pcur->info.tel);
		printf("%-4s ", pcur->info.addr);
		printf("\n");
		pcur = pcur->next;
	}

}


//查找通讯录数据
void FindContact(contact* con)
{
	assert(con);
	char name[NAME_MAX];
	printf("请输入您要查找的联系人姓名:\n");
	scanf("%s", name);
	contact* pcur = con;
	while (pcur != NULL && strcmp(pcur->info.name, name) != 0)
	{
		pcur = pcur->next;
	}
	if (pcur == NULL)
	{
		printf("您要查找的联系人不存在!\n");
		return;
	}
	else
	{
		printf("%-4s %-4s %-4s %-4s %-4s\n", "姓名", "性别", "年龄", "电话", "地址");
		printf("%-4s ", pcur->info.name);
		printf("%-4s ", pcur->info.sex);
		printf("%-4d ", pcur->info.age);
		printf("%-4s ", pcur->info.tel);
		printf("%-4s ", pcur->info.addr);
		printf("\n");
	}
}

void ModifyContact(contact** con)
{
	assert(con);
	assert(*con);

	printf("请输入您要修改的联系人姓名:\n");
	char name[NAME_MAX];
	scanf("%s", name);
	contact* pcur = *con;
	while (pcur != NULL && strcmp(pcur->info.name, name) != 0)
	{
		pcur = pcur->next;
	}
	if (pcur == NULL)
	{
		printf("您要修改的联系人不存在!\n");
		return;
	}
	else
	{
		printf("请输入修改后的联系人姓名:\n");
		scanf("%s", pcur->info.name);
		printf("请输入修改后的联系人性别:\n");
		scanf("%s", pcur->info.sex);
		printf("请输入修改后的联系人年龄:\n");
		scanf("%d", &pcur->info.age);
		printf("请输入修改后的联系人电话:\n");
		scanf("%s", pcur->info.tel);
		printf("请输入修改后的联系人地址:\n");
		scanf("%s", pcur->info.addr);
		printf("\n");
		printf("联系人修改成功!\n");
	}
}

void DestroyContact(contact** con)
{
	contact* prev = NULL;
	contact* pcur = *con;
	while (pcur!= NULL)
	{
		prev = pcur;
		pcur = pcur->next;
		free(prev);
		prev = NULL;
	}
	free(prev);
	prev = NULL;
}

test.c:

测试文件相对来说代码比较少。

需要注意,顺序表是直接创建的结构体,这里是创建一个结构体指针。

#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include "slcontact.h"



int main()
{
	contact* s1;//这里要用指针
	InitContact(&s1);//初始化通讯录
	int num = 0;
	do 
	{
		Menu();	
		printf("请选择您要进行的操作:\n");
		scanf("%d", &num);
		switch (num)
		{
		case 0:  DestroyContact(&s1);
			break;
		case 1:  AddContact(&s1);
			break;
		case 2:  DelContact(&s1);
			break;
		case 3:  FindContact(s1);
			break;
		case 4:  ShowContact(s1);
			break;
		case 5:  ModifyContact(&s1);
			break;
		default: printf("输入错误,请重新输入\n");
			break;
		}
	} while (num);

	return 0;
}






这样,一个通讯录就写完了。这里没有添加文件操作,感兴趣可以自行扩展。

你可能感兴趣的:(数据结构)