今天重新把通讯录的程序完善了一下,可以完结了,通讯录这种程序真的很适合来训练结构体、指针和链表方面的知识。
贴代码:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#define MAX 100
/*建立结构体链表,固定结构,背下来*/
typedef struct people
{
char name[MAX];
char sex[MAX];
int age;
long long int tel;
char addr[MAX];
struct people *pNext;
}Node, *pNode; /*Node为结构体变量,pNode为结构体指针变量,也可以只写Node,在定义指针的时候写成(Node *p)*/
/*定义全局变量,记录最后录入的联系人的节点数*/
int num = 0;
int main(void)
{
int flag;
char ch;
pNode pHead = NULL; /*首次定义头指针需要置零*/
pNode CreatList(void);
pNode CreatMember(pNode);
void DeleteMember(pNode);
void DeleteList(pNode);
void FindMember(pNode);
void ModifyMember(pNode);
void TraverseList(pNode);
void DeleteAll(pNode);
void SortList(pNode);
while (1)
{
printf("1.添加联系人信息\n2.删除指定联系人信息\n3.查找指定联系人信息\n4.修改指定联系人信息\n5.显示所有联系人信息\n6.清空所有联系人\n7.以名字排序所有联系人\n");
printf("请输入要进行的操作:");
scanf_s("%d", &flag);
printf("\n");
while (getchar() != '\n')
{
ch = getchar();
}
switch (flag)
{
case 1:
{
/*首次录入联系人*/
if (num == 0)
{
pHead = CreatList();
}
/*重复录入联系人*/
else
{
pHead = CreatMember(pHead);
}
printf("\n");
break;
}
case 2:
{
/*剩余联系人超过1人时,令链表为空表*/
if (num == 1)
{
DeleteList(pHead);
}
/*正常删除*/
else
{
DeleteMember(pHead);
}
printf("\n");
break;
}
case 3:
{
FindMember(pHead);
printf("\n");
break;
}
case 4:
{
ModifyMember(pHead);
printf("\n");
break;
}
case 5:
{
/*链表中有联系人时,正常遍历*/
if (num > 0)
{
TraverseList(pHead);
}
/*空链表*/
else
{
printf("无联系人。");
}
printf("\n");
break;
}
case 6:
{
DeleteAll(pHead);
printf("\n");
break;
}
case 7:
{
SortList(pHead);
printf("\n");
break;
}
}
printf("现有%d个联系人。\n\n\n", num);
}
return 0;
}
/*首次录入联系人,建立一个新的链表*/
pNode CreatList(void)
{
/*定义头节点、尾节点、新节点*/
pNode pHead, pTail, pNew;
pHead = (pNode)malloc(sizeof(Node)); /*为头指针开辟一块内存*/
pTail = pHead; /*空链表的头节点就是尾节点*/
pTail->pNext = NULL; /*尾节点指向空值*/
/*输入数据给新节点*/
pNew = (pNode)malloc(sizeof(Node)); /*为新节点开辟内存*/
printf("请输入联系人姓名:");
scanf_s("%s", &pNew->name, MAX);
printf("请输入联系人性别:");
scanf_s("%s", &pNew->sex, MAX);
printf("请输入联系人年龄:");
scanf_s("%d", &pNew->age);
printf("请输入联系人电话:");
scanf_s("%lld", &pNew->tel);
printf("请输入联系人地址:");
scanf_s("%s", &pNew->addr, MAX);
/*新节点接入链表*/
pTail->pNext = pNew; /*令原来的尾节点指向新节点*/
pNew->pNext = NULL; /*新节点指向空值*/
pTail = pNew; /*新节点成为新的尾节点,原来的尾节点成为中间节点*/
/*录入联系人+1*/
num++;
return pHead;
}
/*重复录入联系人,将新的联系人接到原有的链表中*/
pNode CreatMember(pNode p)
{
/*定义新链表的头节点、尾节点、新节点、临时节点*/
pNode pHead, pTail, pNew, pSwap, pRepeat;
char a[MAX];
pHead = p; /*将原有的链表赋给pHead*/
pRepeat = p->pNext;
/*寻找原有链表的最后一个节点*/
pSwap = NULL; /*定义一个pVal来临时保存最后一个节点的数据*/
while (p != NULL)
{
pSwap = p; /*pVal始终为p的前一个节点,当遍历结束时,p为空,pVal即为最后一个节点*/
p = p->pNext;
}
pTail = pSwap; /*令pTail成为链表最后一个节点*/
pTail->pNext = NULL; /*尾节点指向空值*/
/*输入数据给新节点*/
pNew = (pNode)malloc(sizeof(Node));
printf("请输入联系人姓名:");
scanf_s("%s", &pNew->name, MAX);
printf("请输入联系人性别:");
scanf_s("%s", &pNew->sex, MAX);
printf("请输入联系人年龄:");
scanf_s("%d", &pNew->age);
printf("请输入联系人电话:");
scanf_s("%lld", &pNew->tel);
printf("请输入联系人地址:");
scanf_s("%s", &pNew->addr, MAX);
/*判断新录入的联系人是否已存在*/
while (pRepeat != NULL)
{
if (strcmp(pNew->name, pRepeat->name) == 0)
{
printf("联系人已存在!\n");
return pHead;
}
pRepeat = pRepeat->pNext;
}
/*新节点接入链表*/
pTail->pNext = pNew; /*令原来的尾节点指向新节点*/
pNew->pNext = NULL; /*新节点指向空值*/
pTail = pNew; /*新节点成为新的尾节点,原来的尾节点成为中间节点*/
/*录入联系人+1*/
num++;
return pHead;
}
/*删除第一个联系人,令链表为空*/
void DeleteList(pNode p)
{
/*定义临时节点*/
pNode pSwap;
char a[MAX];
printf("请输入要删除的联系人姓名:");
pSwap = p; /*将联系人链表头节点赋值给临时节点*/
scanf_s("%s", a, MAX);
if (strcmp(pSwap->pNext->name, a) == 0) /*检查姓名是否匹配*/
{
pSwap = NULL;
/*删除联系人-1*/
num--;
}
else
{
printf("联系人不存在!");
}
}
/*删除指定联系人*/
void DeleteMember(pNode p)
{
/*定义临时节点*/
pNode pSwap, pVal;
char a[MAX];
printf("请输入要删除的联系人姓名:");
pSwap = p; /*将联系人链表头节点赋值给临时节点*/
pVal = p;
scanf_s("%s", a, MAX);
/*遍历*/
while (pSwap != NULL)
{
if (strcmp(pSwap->name, a) == 0) /*检查姓名是否匹配*/
{
pVal->pNext = pVal->pNext->pNext;
break;
}
pVal = pSwap; /*保存要删除的节点的前一节点*/
pSwap = pSwap->pNext;
}
if (pSwap == NULL)
{
printf("未找到联系人!\n");
}
/*删除联系人-1*/
num--;
}
/*查找联系人*/
void FindMember(pNode p)
{
/*定义临时节点*/
pNode pSwap;
char a[MAX];
printf("请输入要查找的联系人姓名:");
scanf_s("%s", a, MAX);
pSwap = p->pNext; /*将联系人链表头节点赋值给临时节点*/
/*遍历*/
while (pSwap != NULL)
{
if (strcmp(pSwap->name, a) == 0) /*检查姓名是否*/
{
printf("%s ", pSwap->name);
printf("%s ", pSwap->sex);
printf("%d ", pSwap->age);
printf("%lld ", pSwap->tel);
printf("%s\n", pSwap->addr);
break;
}
pSwap = pSwap->pNext;
}
if (pSwap == NULL)
{
printf("未找到联系人!\n");
}
}
/*修改联系人*/
void ModifyMember(pNode p)
{
/*定义临时节点*/
pNode pSwap;
char a[MAX];
printf("请输入要查找的联系人姓名:");
scanf_s("%s", a, MAX);
pSwap = p->pNext; /*将联系人链表头节点赋值给临时节点*/
/*遍历*/
while (pSwap != NULL)
{
if (strcmp(pSwap->name, a) == 0) /*检查姓名是否*/
{
/*输入数据给新节点*/
printf("请输入联系人姓名:");
scanf_s("%s", &pSwap->name, MAX);
printf("请输入联系人性别:");
scanf_s("%s", &pSwap->sex, MAX);
printf("请输入联系人年龄:");
scanf_s("%d", &pSwap->age);
printf("请输入联系人电话:");
scanf_s("%lld", &pSwap->tel);
printf("请输入联系人地址:");
scanf_s("%s", &pSwap->addr, MAX);
break;
}
pSwap = pSwap->pNext;
}
if (pSwap == NULL)
{
printf("未找到联系人!\n");
}
}
/*遍历输出所有联系人*/
void TraverseList(pNode pHead)
{
/*定义临时节点*/
pNode p;
p = pHead->pNext; /*把pHead->pNext而不是pHead赋给p,是因为pHead的数据域本身没有意义,因此只需要赋值pHead->pNext,即将第一个节点的数据域和指针域赋给p*/
/*执行遍历*/
while (p != NULL)
{
printf("%s ", p->name);
printf("%s ", p->sex);
printf("%d ", p->age);
printf("%lld ", p->tel);
printf("%s\n", p->addr);
p = p->pNext;
}
}
/*删除第一个联系人,令链表为空*/
void DeleteAll(pNode p)
{
/*定义临时节点*/
pNode pSwap;
/*链表清空*/
pSwap = p; /*将联系人链表头节点赋值给临时节点*/
pSwap = NULL;
/*联系人数量归零*/
num = 0;
}
/*排序*/
void SortList(pNode pp)
{
/*定义临时节点*/
pNode p, q;
int i, j, m = num;
/*进行num-1轮冒泡排序*/
for (i = 0; i < num - 1; i++)
{
/*头指针重置*/
p = pp;
q = pp->pNext;
/*单论冒泡排序,将最大的数送到最下面*/
for (j = 0; j < m - 1; j++)
{
if (q->name[0] > q->pNext->name[0])
{
p->pNext = q->pNext;
q->pNext = q->pNext->pNext;
p->pNext->pNext = q;
q = p->pNext;
}
q = q->pNext;
p = p->pNext;
}
m--;
}
}
在这边写一个完整的链表冒泡排序单步教程吧,免得以后忘记了。
首先说一下,关于“p->next = q->next”语句的理解:
① “p->next”看作一个过程,是个动词,理解为“p的下一个节点是XX”;
② “q->next”看作一个整体,是个名词,代表一个节点,理解为“p的下一个节点”。
下面进入正题,我们来分析一下以下四条语句对应的链表结构的变化,用图表示:
p->pNext = q->pNext;
q->pNext = q->pNext->pNext;
p->pNext->pNext = q;
q = p->pNext;
- 先介绍一下这四条语句实现的功能,以下图为例,主要实现A和B两个节点的交换。
- “p->pNext = q->pNext”的含义是:p的next指针指向“q->pNext”节点,也就是B。
- “q->pNext = q->pNext->pNext”的含义是:q的next指针指向“q->pNext->pNext”节点,也就是C。
- “p->pNext->pNext = q”的含义是:p->pNext(B)的next指针指向“q”节点,也就是A。
- “q = p->pNext”的含义是:让B为q,A为q->pNext(原来是A为q,B为q->pNext)。
- 最终交完之后的链表如下。