一.通訊錄的功能介紹
1.基于單鏈表實(shí)現(xiàn)通訊錄
(1). 知識(shí)要求
C語(yǔ)言基礎(chǔ)要求:結(jié)構(gòu)體、動(dòng)態(tài)內(nèi)存管理、單鏈表、文件件操作
(2). 功能要求
1)至少能夠存儲(chǔ)100個(gè)人的通訊信息
2)能夠保存用戶信息:名字、性別、年齡、電話、地址等
3)增加聯(lián)系人信息
4)刪除指定聯(lián)系人
5)查找制定聯(lián)系人
6)修改指定聯(lián)系人
7)顯示聯(lián)系人信息
二.通訊錄的代碼實(shí)現(xiàn)
1.通訊錄的底層結(jié)構(gòu)(單鏈表)
(1).思路展示
由于,通訊錄是基于單鏈表實(shí)現(xiàn)的,所以掌握基本的單鏈表的結(jié)構(gòu)代碼,非常重要~!
(2).底層代碼實(shí)現(xiàn)(單鏈表)
1.單鏈表頭文件 —— (函數(shù)的定義)
SList.h
#pragma once
#include"contact.h"
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//創(chuàng)建鏈表節(jié)點(diǎn)結(jié)構(gòu)
typedef struct ContactInfo SLDatatype;
typedef struct SListNode
{
SLDatatype data;//要保存的數(shù)據(jù)
struct SListNode* next;
}SLNode;
//創(chuàng)建幾個(gè)節(jié)點(diǎn)組成鏈表,并且打印鏈表
//打印
void SLNPrint(SLNode* phead);
//尾插
void SLNPushBack(SLNode** pphead, SLDatatype x);
//頭插
void SLNPushFront(SLNode** pphead, SLDatatype x);
//尾刪
void SLNPopBack(SLNode** pphead);
//頭刪
void SLNPopFront(SLNode** pphead);
//在指定位置插入刪除
//
//查找指定的pos
SLNode* SLNFind(SLNode** pphead, SLDatatype x);
//在指定位置之前插入
void SLNInsrt(SLNode** pphead, SLNode* pos, SLDatatype x);
//在指定位置之后插入刪除
void SLNInsrtAfter(SLNode* pos, SLDatatype x);
//刪除指定位置的數(shù)據(jù)
void SLNErase(SLNode** pphead, SLNode* pos);
//刪除指定位置之后的數(shù)據(jù)
void SLNEraseAfter(SLNode* pos);
//銷毀鏈表
void SLNDestroy(SLNode** pphead);
2.單鏈表的源文件 ——(函數(shù)的實(shí)現(xiàn))
SList.c
#include"SList.h"
//打印
//void SLNPrint(SLNode* phead)
//{
// //循環(huán)打印
// //可以用phead直接來訪問,但是注意,當(dāng)代碼走到
// //第16行的時(shí)候,此時(shí)phead已經(jīng)變成NULL了
// //若代碼沒寫完,我還要繼續(xù)使用指向第一個(gè)節(jié)點(diǎn)的地址時(shí),這時(shí)我就
// //找不到第一個(gè)節(jié)點(diǎn)的地址
// //所以為了避免第一個(gè)節(jié)點(diǎn)被更改,要定義一個(gè)新的來代替
// SLNode* pcur = phead;
// while (pcur)
// {
// printf("%d ->", pcur->data);
// pcur = pcur->next;
// }
// printf("NULL\n");
//}
//創(chuàng)建新的節(jié)點(diǎn)
SLNode* SLByNode(SLDatatype x)
{
//開辟新的空間
SLNode* node = (SLNode*)malloc(sizeof(SLNode));
node->data = x;
node->next = NULL;
return node;
}
//尾插
void SLNPushBack(SLNode** pphead, SLDatatype x)
{
SLNode* node = SLByNode(x);
//判斷鏈表是否為空,如果為空,直接插入
if (*pphead == NULL)
{
*pphead = node;
return;
}
//說明鏈表不為空 ,找尾
SLNode* pcur = *pphead;
while (pcur->next != NULL)
{
pcur = pcur->next;
}
pcur->next = node;
}
//頭插
void SLNPushFront(SLNode** pphead, SLDatatype x)
{
//創(chuàng)建新的節(jié)點(diǎn)
SLNode* node = SLByNode(x);
//讓新的節(jié)點(diǎn)跟頭節(jié)點(diǎn)連起來
node->next = *pphead;
//再讓新節(jié)點(diǎn)成為頭節(jié)點(diǎn)
*pphead = node;
}
//尾刪
void SLNPopBack(SLNode** pphead)
{
//先判斷鏈表是否為空,如果為空就無法進(jìn)行刪除操作
assert(pphead);
//還要判斷第一個(gè)節(jié)點(diǎn)不能為空
assert(*pphead);
//只有一個(gè)節(jié)點(diǎn)的情況
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
return;
}
//有多個(gè)節(jié)點(diǎn)的情況
//先找到尾節(jié)點(diǎn)/尾節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)
SLNode* ptail = *pphead;
SLNode* prev = NULL;
while (ptail->next)
{
prev = ptail;
ptail = prev->next;
}
//讓尾節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)指向不再指向尾節(jié)點(diǎn),而是指向尾節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
prev->next = ptail->next;
//然后在刪除尾節(jié)點(diǎn)
free(ptail);
//為什么要將ptaii置為空指針?代碼后面明明沒有再使用ptail,因?yàn)榇蛴℃湵淼拇a有判斷節(jié)點(diǎn)的地址是否為空
ptail = NULL;
}
void SLNPopFront(SLNode** pphead)
{
//判斷鏈表不能為空
assert(pphead);
//判斷頭節(jié)點(diǎn)不能為空
assert(*pphead);
SLNode* del = *pphead;
*pphead = (*pphead)->next;
free(del);
//出于代碼規(guī)范
del = NULL;
}
//查找指定的pos
//SLNode* SLNFind(SLNode** pphead, SLDatatype x)
//{
// assert(pphead);
// SLNode* pcur = *pphead;
// while (pcur)
// {
// if (pcur->data == x)
// {
// return pcur;
// }
// pcur = pcur->next;
// }
// //出循環(huán),代表沒找到
// return NULL;
//}
//在指定位置之前插入
void SLNInsrt(SLNode** pphead, SLNode* pos, SLDatatype x)
{
SLNode* node = SLByNode(x);
assert(pphead);
assert(*pphead);
//只有一個(gè)節(jié)點(diǎn)的情況 == pos就是頭節(jié)點(diǎn),直接進(jìn)行頭插
if (pos == *pphead)
{
node->next = *pphead;
*pphead = node;
return;
}
//有多個(gè)節(jié)點(diǎn)的情況
//找pos的前一個(gè)節(jié)點(diǎn)
SLNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
//這里的插入節(jié)點(diǎn)的處理順序可以調(diào)換
prev->next = node;
node->next = pos;
}
//在指定的位置之后插入
void SLNInsrtAfter(SLNode* pos, SLDatatype x)
{
assert(pos);
SLNode* node = SLByNode(x);
// node pos node->next
node->next = pos->next;
pos->next = node;
}
//刪除指定位置的節(jié)點(diǎn)
void SLNErase(SLNode** pphead, SLNode* pos)
{
assert(pphead);
assert(*pphead);
assert(pos);
if (pos == *pphead)
{
*pphead = (*pphead)->next;
free(pos);
return;
}
//找pos的前一個(gè)節(jié)點(diǎn)
SLNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next;
free(pos);
pos = NULL;
}
//刪除指定位置之后的節(jié)點(diǎn)
void SLNEraseAfter(SLNode* pos)
{
assert(pos);
assert(pos->next);
SLNode* del = pos->next;
pos->next = del->next;
free(del);
del = NULL;
}
//銷毀鏈表
void SLNDestroy(SLNode** pphead)
{
assert(*pphead);
SLNode* pcur = *pphead;
while (pcur)
{
SLNode* next = pcur->next;
free(pcur);
pcur = next;
}
*pphead = NULL;
}
2.通訊錄上層代碼實(shí)現(xiàn)(通訊錄結(jié)構(gòu))
(1)思路展示
1)由于,通訊錄是基于單鏈表實(shí)現(xiàn)的。
2)所以,通訊錄上層代碼,只需要在上層代碼的頭文件代碼中創(chuàng)建一個(gè)保存聯(lián)系人的結(jié)構(gòu),然后再定義通訊錄功能函數(shù)即可。
3)接著在通訊錄上層代碼的源文件中將這些功能函數(shù)實(shí)現(xiàn)即可。
4)基于前面,我們已經(jīng)知道,通訊錄是單鏈表實(shí)現(xiàn)的,所以在實(shí)現(xiàn)通訊錄功能函數(shù)時(shí),只需要在通訊錄上層代碼的源文件中,加上單鏈表的頭文件就可以調(diào)運(yùn)單鏈表的函數(shù)來實(shí)現(xiàn)通訊錄了。
(2) 上層代碼的實(shí)現(xiàn)(順序表)
1.通訊錄的頭文件 —— (函數(shù)的定義)
contact.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#pragma once
#define NAME_MAX 100
#define SEX_MAX 4
#define TEL_MAX 15
#define ADDR_MAX 100
//前置聲明
typedef struct SListNode contact;
//用戶數(shù)據(jù)
typedef struct ContactInfo
{
char name[NAME_MAX];
char sex[SEX_MAX];
int age;
char tel[TEL_MAX];
char addr[ADDR_MAX];
}CInfo;
//初始化通訊錄
void InitContact(contact** pcon);
//添加通訊錄數(shù)據(jù)
void AddContact(contact** pcon);
//刪除通訊錄數(shù)據(jù)
void DelContact(contact** pcon);
//展示通訊錄數(shù)據(jù)
void ShowContact(contact* pcon);
//查找通訊錄數(shù)據(jù)
void FindContact(contact* pcon);
//修改通訊錄數(shù)據(jù)
void ModifyContact(contact** pcon);
//銷毀通訊錄數(shù)據(jù)
void DestroyContact(contact** pcon);
2.通訊錄的源文件 —— (函數(shù)的實(shí)現(xiàn))
contact.c
#include"contact.h"
#include"SList.h"
void LoadContact(contact** pcon) {
FILE* pf = fopen("contact.txt", "rb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//循環(huán)讀取文件數(shù)據(jù)
CInfo info;
while (fread(&info, sizeof(info), 1, pf))
{
SLNPushBack(pcon, info);
}
printf("歷史數(shù)據(jù)導(dǎo)入通訊錄成功!\n");
}
//初始化通訊錄/建立頭節(jié)點(diǎn)
void InitContact(contact** pcon)
{
LoadContact(pcon);
}
//添加通訊錄數(shù)據(jù)
void AddContact(contact** pcon)
{
//接下來獲取的都是結(jié)構(gòu)體CInfo結(jié)構(gòu)體里要求的數(shù)據(jù)
CInfo info;
printf("請(qǐng)輸入聯(lián)系人姓名:\n");
scanf("%s", info.name);
printf("請(qǐng)輸入聯(lián)系人性別:\n");
scanf("%s", info.sex);
printf("請(qǐng)輸入聯(lián)系人年齡:\n");
scanf("%d", &info.age);
printf("請(qǐng)輸入聯(lián)系人電話:\n");
scanf("%s", info.tel);
printf("請(qǐng)輸入聯(lián)系人住址:\n");
scanf("%s", info.addr);
//聯(lián)系人數(shù)據(jù)都獲取到了,并保存到了結(jié)構(gòu)體info中
//往通訊錄(鏈表)中插入數(shù)據(jù)
SLNPushBack(pcon, info);
}
contact* FindByName(contact* pcon, char name[])
{
contact* cur = pcon;
while (cur)
{
if (strcmp(cur->data.name, name) == 0) {
return cur;
}
cur = cur->next;
}
return NULL;
}
//刪除通訊錄數(shù)據(jù)
void DelContact(contact** pcon)
{
//直接強(qiáng)制用戶使用名稱來查找
printf("請(qǐng)輸入要?jiǎng)h除的聯(lián)系人姓名:\n");
char name[NAME_MAX];
scanf("%s", name);
contact* findidex = FindByName(*pcon, name);
if (findidex)
{
(*pcon)->next = findidex->next;
//找到了,要?jiǎng)h除findidex位置的數(shù)據(jù)
SLNErase(pcon, findidex);
printf("刪除成功\n");
}
else {
printf("要?jiǎng)h除的聯(lián)系人不存在!\n");
return;
}
}
//展示通訊錄數(shù)據(jù)
void ShowContact(contact* pcon)
{
contact* cur;
cur = pcon;
//打印表頭
printf("%s %s %s %s %s\n", "姓名", "性別", "年齡", "電話", "住址");
while (cur)
{
printf("%-5s %-5s %-4d %-4s %-4s\n",
cur->data.name,
cur->data.sex,
cur->data.age,
cur->data.tel,
cur->data.addr);
cur = cur->next;
}
}
//查找通訊錄數(shù)據(jù)
void FindContact(contact* pcon)
{
//直接強(qiáng)制用戶使用名稱來查找
printf("請(qǐng)輸入你要查找的聯(lián)系人\n");
char name[NAME_MAX];
scanf("%s", name);
contact* findidex = FindByName(pcon, name);
if (findidex==NULL)
{
printf("沒有此聯(lián)系人\n");
return;
}
else
{
printf("找到了:\n");
printf("%s %s %s %s %s\n", "姓名", "性別", "年齡", "電話", "住址");
printf("%-5s %-5s %-4d %-4s %-4s\n",
findidex->data.name,
findidex->data.sex,
findidex->data.age,
findidex->data.tel,
findidex->data.addr);
}
}
//修改聯(lián)系人選項(xiàng)
void MondifyMenu()
{
printf("***************修改聯(lián)系人選項(xiàng)****************\n");
printf("***** 1.修改聯(lián)系人名字 2.修改聯(lián)系人性別*****\n");
printf("***** 3.修改聯(lián)系人年齡 4.修改聯(lián)系人電話*****\n");
printf("***** 5.修改聯(lián)系人住址 0.退出刪除選項(xiàng)*******\n");
printf("******************************************\n");
}
//修改通訊錄數(shù)據(jù)
void ModifyContact(contact** pcon)
{
//直接強(qiáng)制用戶使用名稱來查找
printf("請(qǐng)輸入你要修改的聯(lián)系人\n");
char name[NAME_MAX];
scanf("%s", name);
contact* findidex = FindByName(*pcon, name);
if (findidex == NULL)
{
printf("沒有你要?jiǎng)h除的聯(lián)系人\n");
return;
}
else {
printf("找到了:\n");
printf("%s %s %s %s %s\n", "姓名", "性別", "年齡", "電話", "住址");
printf("%-5s %-5s %-4d %-4s %-4s\n",
findidex->data.name,
findidex->data.sex,
findidex->data.age,
findidex->data.tel,
findidex->data.addr);
int val = -1;
do {
MondifyMenu();
printf("請(qǐng)選擇你需要修改的信息:\n");
scanf("%d", &val);
switch (val)
{
case 1:
printf("請(qǐng)輸入修改后的聯(lián)系人姓名:\n");
scanf("%s", findidex->data.name);
break;
case 2:
printf("請(qǐng)輸入修改后的聯(lián)系人性別:\n");
scanf("%s", findidex->data.sex);
break;
case 3:
printf("請(qǐng)輸入修改后的聯(lián)系人年齡:\n");
scanf("%d", &findidex->data.age);
break;
case 4:
printf("請(qǐng)輸入修改后的聯(lián)系人電話:\n");
scanf("%s", findidex->data.tel);
break;
case 5:
printf("請(qǐng)輸入修改后的聯(lián)系人住址:\n");
scanf("%s", findidex->data.addr);
break;
case 0:
printf("修改成功\n");
printf("已退出刪除聯(lián)系人選項(xiàng)\n");
break;
default:
printf("沒有找到要修改的選項(xiàng) 請(qǐng)重新選擇:\n");
break;
}
} while (val != 0);
}
}
void SaveContact(contact* pcon) {
FILE* pf = fopen("contact.txt", "wb");
if (pf == NULL) {
perror("fopen error!\n");
return;
}
//將通訊錄數(shù)據(jù)寫入文件
contact* cur = pcon;
while (cur)
{
fwrite(&(cur->data), sizeof(cur->data), 1, pf);
cur = cur->next;
}
printf("通訊錄數(shù)據(jù)保存成功!\n");
}
void DestroyContact(contact** pcon) {
SaveContact(*pcon);
SLNDestroy(pcon);
}
3.測(cè)試源文件 —— (功能函數(shù)的測(cè)試運(yùn)行)
test.c
#include"contact.h"
#include"SList.h"
void menu()
{
printf("***************通訊錄****************\n");
printf("***** 1.添加聯(lián)系人 2.刪除聯(lián)系人*****\n");
printf("***** 3.修改聯(lián)系人 4.查找聯(lián)系人*****\n");
printf("***** 5.查看通訊錄 0.退出通訊錄*****\n");
printf("*************************************\n");
}
int main()
{
int op = -1;
contact* con=NULL;
InitContact(&con);
do {
menu();
printf("請(qǐng)選擇你要進(jìn)行的操作:\n");
scanf("%d", &op);
switch (op)
{
case 1:
AddContact(&con);
break;
case 2:
DelContact(&con);
break;
case 3:
ModifyContact(&con);
break;
case 4:
FindContact(con);
break;
case 5:
ShowContact(con);
break;
case 0:
printf("已退出通訊錄\n");
break;
default:
printf("系統(tǒng)里沒有找到你需要進(jìn)行的操作,請(qǐng)重新輸入:\n");
break;
}
} while (op != 0);
DestroyContact(&con);
return 0;
}
3.通訊錄代碼運(yùn)行展示(數(shù)據(jù)只用于測(cè)試,無實(shí)際意義)
(1) 測(cè)試展示
文章來源:http://www.zghlxwxcb.cn/news/detail-712988.html
(2) 總結(jié)升華
這里只是展示基于單鏈表實(shí)現(xiàn)通訊錄的大致框架,和一些基本功能,有興趣,能力的小伙伴,也可以下去拓展一下通訊錄的其他功能,優(yōu)化的更加完善,美觀的通訊錄。
感謝學(xué)習(xí)!文章來源地址http://www.zghlxwxcb.cn/news/detail-712988.html
到了這里,關(guān)于【(數(shù)據(jù)結(jié)構(gòu))—— 基于單鏈表實(shí)現(xiàn)通訊錄】的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!