【數據結構】4.單鏈表實現通訊錄

在上一篇文章我們學會了用單鏈表來實現各種方法,在這一篇文章我們將在單鏈表的基礎上實現通訊錄。

0、準備工作

實現通訊錄之前,我們還需要在單鏈表的基礎上添加2個文件,頭文件Contact.h和源文件Contact.c。Contact.c來實現通訊錄方法的聲明,而Contact.h來實現通訊錄的具體方法。
通訊錄的數據其實就是存儲在單鏈表上的,只不過變成了一個結構體,因此我們需要在Contact.h定義一個聯系人數據的結構體。
如下圖所示:
在這里插入圖片描述
代碼如下:

typedef struct PersonInfo
{char name[NAME_MAX];char gender[GENDER_MAX];int age;char tel[TEL_MAX];char addr[ADDR_MAX];
}PeoInfo;

為了代碼有更好的延展性,我們還可以對數組的內存大小進行宏定義,在Contact.h的頭部定義:

#define NAME_MAX 10
#define GENDER_MAX 10
#define TEL_MAX 20
#define ADDR_MAX 100

由于我們是再單鏈表的基礎上進行的,所以我們可以對單鏈表重新起個名字叫做通訊錄,在Contact.h中定義:typedef struct SListNode contact;

由于我們是將類型由整型類型改為結構體類型,那么我們還需要再SList,h中將類型重定義一下:typedef struct PersonInfo SLDataType;

接著就可以在Contact.h中聲明一系列的方法:

//通訊錄的初始化
void InitContact(contact** con);//添加通訊錄數據
void AddContact(contact** con);//刪除通訊錄數據
void DelContact(contact** con);//展示通訊錄數據
void ShowContact(contact** con);//查找通訊錄數據
void FindContact(contact** con);//修改通訊錄數據
void ModifyContact(contact** con);//銷毀通訊錄數據
void DestroyContact(contact** con);//讀取文件內容到通訊錄
void LoadContact(contact** con);//保存通訊錄數據到文件
void SaveContact(contact** con);

接下來再在Contact.c進行方法的實現,在實現之前我們需要包含以下頭文件:

#include"Contact.h"
#include"SList.h"

1、初始化通訊錄

初始化代碼:

void InitContact(contact** con)
{LoadContact(con);
}

通訊錄的初始化實際上就是將文件的數據導入到通訊錄,確保通訊錄一開始就擁有之前的數據,而不是一個空殼。
將文件數據導入到通訊錄代碼如下:

void LoadContact(contact** con)
{//打開文件FILE* pf = fopen("contact.txt", "rb");if (pf == NULL){perror("fopen fail!");return;}//定義通訊錄變量PeoInfo info;//依次讀取文件數據while (fread(&info, sizeof(info), 1, pf)){//將文件數據尾插到通訊錄中SLTPushBack(con, info);}printf("歷史通訊錄數據導入成功!\n");//有開有閉fclose(pf);
}

2、添加通訊錄數據

思路:創建通訊錄局部變量,輸入對應信息后,再尾插到通訊錄中。

void AddContact(contact** con)
{PeoInfo info;printf("請輸入要添加的聯系人姓名:");scanf("%s", info.name);printf("請輸入要添加的聯系人性別:");scanf("%s", info.gender);printf("請輸入要添加的聯系人年齡:");scanf("%d", &info.age);printf("請輸入要添加的聯系人電話:");scanf("%s", info.tel);printf("請輸入要添加的聯系人地址:");scanf("%s", info.addr);SLTPushBack(con, info);printf("添加聯系人成功!\n");
}

再進行測試:

int main()
{contact* con=NULL;AddContact(&con);return 0;
}

運行結果:

我們再進行調試觀察是否真正的插入成功:

可以觀察到確實成功插入數據了!

3、展示通訊錄數據

為了方便我們觀察方法是否成功進行,我們可以先編寫展示通訊錄數據的方法。

思路:先打印表頭,再創建指針cur指向頭結點,遍歷整個通訊錄,依次打印對應的信息。

void ShowContact(contact* con)
{printf("%-10s %-4s %-4s %-11s %-20s\n", "姓名", "性別", "年齡", "電話", "地址");contact* cur = con;while (cur){printf("%-10s %-4s %4s %-11s %-20s\n", cur->data.name,cur->data.gender,cur->data.age,cur->data.tel,cur->data.addr);cur = cur->next;}
}

再進行測試:

int main()
{contact* con=NULL;AddContact(&con);ShowContact(con);return 0;
}

通訊錄數據顯示成功!

4、刪除通訊錄數據

在進行刪除,修改等一系列操作的時候,我們首先需要知道刪除或修改的對象是誰,因此還需要一個函數專門根據姓名來查找到聯系人,再進行后續的一系列操作。

查找思路:傳一個頭結點,和要查找的姓名,先創建指針指向頭結點,再遍歷通訊錄,看要查找的名字是否在通訊錄中,在就返回下標,不在就返回空。

contact* FindByName(contact* con, char name[])
{contact* cur = con;while (cur){if (0 == strcmp(name, cur->data.name)){return cur;}cur = cur->next;}//沒找到返回NULLreturn NULL;
}

接著就可以刪除通訊錄數據了。
思路:輸入要查找的姓名,調用查找函數找到下標,如果下標為空就表示沒有找到,并且終止程序,下標不為空就執行刪除指定位置數據的操作。

void DelContact(contact** con)
{char name[NAME_MAX];printf("請輸入要刪除的聯系人姓名:");scanf("%s", name);contact* pos = FindByName(*con, name);if (pos == NULL){printf("你要刪除的聯系人不存在!\n");return;}SLTErase(con, pos);printf("刪除成功!\n");
}

再進行測試:

int main()
{contact* con=NULL;AddContact(&con);AddContact(&con);ShowContact(con);DelContact(&con);ShowContact(con);return 0;
}

運行結果:

我們可以觀察到刪除成功!

5、查找通訊錄數據

思路:輸入要查找的姓名,調用查找函數找到下標,下標為空就沒找到并終止程序,不為空就直接展示下標所對應的數據。

void FindContact(contact** con)
{char name[NAME_MAX];printf("請輸入要查找的聯系人姓名:");scanf("%s", name);contact* pos = FindByName(*con, name);if (pos == NULL){printf("你要查找的聯系人不存在!\n");return;}printf("查找成功!\n");//打印下標對應的數據printf("%-10s %-4s %-4s %-11s %-20s\n", "姓名", "性別", "年齡", "電話", "地址");printf("%-10s %-4s %-4d %-11s %-20s\n",pos->data.name,pos->data.gender,pos->data.age,pos->data.tel,pos->data.addr);
}

再進行測試:

int main()
{contact* con=NULL;AddContact(&con);AddContact(&con);FindContact(&con);return 0;
}

運行結果:

6、修改通訊錄數據

思路:輸入要查找的姓名,調用查找函數找到下標,下標為空就沒找到并終止程序,不為空就直接修改下標所對應的數據。

void ModifyContact(contact** con)
{char name[NAME_MAX];printf("請輸入要修改的聯系人姓名:");scanf("%s", name);contact* pos = FindByName(*con, name);if (pos == NULL){printf("你要修改的聯系人不存在!\n");return;}//修改下標對應的數據printf("請輸入要修改的姓名:");scanf("%s", pos->data.name);printf("請輸入要修改的性別:");scanf("%s", pos->data.gender);printf("請輸入要修改的年齡:");scanf("%d", &pos->data.age);printf("請輸入要修改的電話:");scanf("%s", pos->data.tel);printf("請輸入要修改的地址:");scanf("%s", pos->data.addr);printf("修改成功!\n");
}

再進行測試:

int main()
{contact* con=NULL;AddContact(&con);ShowContact(con);ModifyContact(&con);ShowContact(con);return 0;
}

運行結果:

修改成功!

7、保存通訊錄數據

在我們實現以上方法后,我們輸入數據之后可以將其保存,下一次再直接導入使用,因此還需要寫一個保存數據的函數。
思路:打開文件,創建指針cur指向頭結點,遍歷單鏈表,依次將cur對應的聯系人數據寫入文件中。

void SaveContact(contact* con)
{FILE* pf = fopen("contact.txt", "wb");if (pf == NULL){perror("fopen fail!");return;}contact* cur = con;while (cur){//將當前節點對應的聯系人數據寫入文件fwrite(&(cur->data), sizeof(PeoInfo), 1, pf);cur = cur->next;}printf("保存成功!\n");fclose(pf);
}

我們再進行測試:

int main()
{contact* con=NULL;AddContact(&con);SaveContact(con);return 0;
}

可以觀察到,數據已經成功被保存到文件中了!

8、銷毀通訊錄

思路:先保存通訊錄數據,再調用單鏈表的銷毀函數。

void DestroyContact(contact** con)
{SaveContact(*con);SListDestroy(con);
}

再進行測試:

int main()
{contact* con = NULL;AddContact(&con);DestroyContact(&con);return 0;
}

在這里插入圖片描述
可以觀察到數據已經成功銷毀了,同時數據已經被存儲到文件中了。

9、通訊錄的完整實現

再實現了上述方法之后,我們就可以在test.c中編寫可視化的操作頁面,通過調用通訊錄的方法來完整實現通訊錄了。
思路:先編寫主界面函數,主函數:輸入值先賦值為-1,通訊錄初始化,再使用do while循環條件輸入0終止,調用主界面,輸入值,根據輸入的值使用switch來執行對應的操作,最后再將通訊錄銷毀。

void menu()
{printf("******************     通訊錄     ******************\n");printf("*********  1、增加聯系人    2、刪除聯系人  **************\n");printf("*********  3、查找聯系人    4、修改聯系人  **************\n");printf("*********  5、展示聯系人    6、保存聯系人  **************\n");printf("*********          0、退出通訊錄           **************\n");
}int main()
{int input = -1;contact* con = NULL;InitContact(&con);do{menu();printf("請選擇你的操作:");scanf("%d", &input);switch (input){case 1:AddContact(&con);break;case 2:DelContact(&con);break;case 3:FindContact(&con);break;case 4:ModifyContact(&con);break;case 5:ShowContact(con);break;case 6:SaveContact(con);break;case 0:printf("退出通訊錄...\n");break;default:printf("輸入錯誤,請重新選擇你的操作:\n");break;}} while (input!=0);DestroyContact(&con);return 0;
}

再進行測試:

發現已經可以實現完整的通訊錄功能了。

點擊在gitee查看完整源代碼

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/901743.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/901743.shtml
英文地址,請注明出處:http://en.pswp.cn/news/901743.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【bash】.bashrc

查看當前路徑文件數量 alias file_num"ls -l | grep ^- | wc -l"查看文件大小 alias file_size"du -sh"alias ll alias ll"ls -ltrh"cd的同時執行ll alias cdcdls; function cdls() {builtin cd "$1" && ll }自定義prompt…

微信小程序實戰案例 - 餐館點餐系統 階段 2 – 購物車

階段?2 – 購物車(超詳細版) 目標 把“加入購物車”做成 全局狀態,任何頁面都能讀寫在本地 持久化(關閉小程序后購物車仍在)新建 購物車頁:數量增減、總價實時計算、去結算入口打 Git?Tag v2.0?cart 1. …

從紅黑樹到哈希表:原理對比與典型場景應用解析(分布式以及布隆過濾器)

在數據結構的世界里,紅黑樹一直以「自平衡二叉查找樹」的身份備受贊譽。憑借紅黑節點的精妙設計,它能將插入、刪除、查找的時間復雜度穩定控制在 ( log ? n ) (\log n) (logn),成為處理有序數據的經典方案。然而,當業務場景對「…

游戲報錯?MFC140.dll怎么安裝才能解決問題?提供多種MFC140.dll丟失修復方案

MFC140.dll 是 Microsoft Visual C 2015 運行庫的重要組成部分,許多軟件和游戲依賴它才能正常運行。如果你的電腦提示 "MFC140.dll 丟失" 或 "MFC140.dll 未找到",說明系統缺少該文件,導致程序無法啟動。本文將詳細介紹 …

《電子類專業:通往科技未來的鑰匙》

一、電子類專業全景概覽 在當今科技飛速發展的時代,電子類專業無疑占據著現代科技體系中基礎與核心的重要地位。從我們日常生活中不可或缺的智能手機、電腦,到推動社會進步的人工智能、大數據技術,再到探索宇宙奧秘的航天航空設備,電子類專業的身影無處不在。它就像一把萬…

Java--批量刪除

前端部分 前端代碼主要負責收集用戶選擇的學生記錄的 id,并將這些 id 發送給后端的 DeleteMoreServlet 進行處理。 批量刪除按鈕綁定點擊事件 $(".deleteMore").on("click",function(){// ... }); 當用戶點擊 “批量刪除” 按鈕時&#xff…

2025年4月份生活有感

今天在5000B培訓的下午,一起入所來的小伙伴,有個申請了深圳大學的博士,已錄取。哎,想起了當年申博時候信心和決心不足,導致后面匆匆的拿了offer去工作。看到同事的選擇還是非常羨慕,想到自己5月份的婚禮&am…

數學建模學習資料免費分享:歷年賽題與優秀論文、算法課程、數學軟件等

本文介紹并分享自己當初準備數學建模比賽時,收集的所有資料,包括歷年賽題與論文、排版模板、算法講解課程與書籍、評分標準、數學建模軟件等各類資料。 最近,準備將自己在學習過程中,到處收集到的各類資料都整理一下,并…

關于 微服務負載均衡 的詳細說明,涵蓋主流框架/解決方案的對比、核心功能、配置示例及總結表格

以下是關于 微服務負載均衡 的詳細說明,涵蓋主流框架/解決方案的對比、核心功能、配置示例及總結表格: 1. 負載均衡的核心概念 負載均衡在微服務中用于將請求分發到多個服務實例,以實現: 高可用性:避免單點故障。性…

個人博客搭建過程

嘗試博客搭建,前面注冊部分很簡單,就不寫了,以我看到的一個博客為基礎,加上我自己的測試結束 1.官網 https://dash.infinityfree.com 前半部分參考: 使用Infinityfree免費虛擬主機搭建一個wordpress網站 2.創建賬戶或登錄您的…

Proxmox VE 網絡配置命令大全

如果對 Proxmox VE 全棧管理感興趣,可以關注“Proxmox VE 全棧管理”專欄,后續文章將圍繞該體系,從多個維度深入展開。 概要:Proxmox VE 網絡配置靈活,滿足虛擬化組網需求。基礎靠橋接實現虛擬機與物理網絡互聯&#x…

【QT入門到晉級】QT打動態庫包及引入動態庫包

前言 本篇為持續更新狀態,內容包含window、Linux下打動態庫包,以及引入動態庫包的方式。 一、window 1、動態庫打包 以百度的OCR接口調用打dll庫為例,以下為qtcreator創建動態庫過程: 1.1Qtcreator創建lib項目 創建成功后&…

Uniapp: 大綱

目錄 一、基礎鞏固1.1、Uniapp:下拉選擇框ba-tree-picker1.2、Uniapp:確認框1.3、Uniapp:消息提示框1.4、Uniapp:列表提示框1.5、Uniapp:獲取當前定位坐標 二、項目配置2.1、Uniapp:修改端口號2.2、Uniapp:…

WPF 從Main()方法啟動

1.去掉App.xaml StartupUri“MainWindow.xaml” 只會讓App.g.cs 不生成這行代碼,但是還是會生成的App.g.cs文件中生成Main方法 this.StartupUri new System.Uri("MainWindow.xaml", System.UriKind.Relative);默認的App.xaml的生成操作是 應用程序定義…

ADB的安裝及抓取日志(2)

三、ADB抓取日志 在使用ADB抓取日志前,首先要保證電腦已經安裝并配置ADB,在上一節已經驗證完成。連接設備:可通過USB或者WI-FI,將安卓設備與電腦連接,并啟用USB調試模式,此處我選擇的是通過電腦與安卓設備…

opencv 灰度實驗

opencv 灰度實驗 1. 最大值法2. 平均值法3. 加權均值法4(直接讀取灰度圖)cv2.IMREAD_GRAYSCALE5內置將原圖轉換為灰度圖cv2.cvtColor()6 兩個極端的灰度值 灰度圖與彩色圖最大的不同就是:彩色圖是由R、G、B三個通道組成,而灰度圖只有一個通道&#xff0c…

『Kubernetes(K8S) 入門進階實戰』實戰入門 - Pod 詳解

『Kubernetes(K8S) 入門進階實戰』實戰入門 - Pod 詳解 Pod 結構 每個 Pod 中都可以包含一個或者多個容器,這些容器可以分為兩類 用戶程序所在的容器,數量可多可少Pause 容器,這是每個 Pod 都會有的一個根容器,它的作用有兩個 可…

用 Vue 3 實現一個拖拽排序表格組件(支持列/行重排、列寬調整)

文章目錄 一、項目初始化1.1 技術棧說明1.2 項目結構圖(Mermaid) 二、構建基礎表格組件2.1 創建基本表格結構 三、實現行拖拽排序3.1 安裝依賴3.2 使用 vuedraggable 實現拖拽 四、實現列寬拖拽調整4.1 基本樣式設置4.2 添加拖拽邏輯 五、實現列拖拽排序…

Python異常處理全面指南

目錄 一、異常處理概述 1.1 什么是異常? 1.2 常見異常類型示例 二、基礎異常捕獲 2.1 簡單異常捕獲語法 2.2 特定異常類型捕獲 三、高級異常處理技術 3.1 完整異常處理語法 3.2 異常傳遞機制 四、主動拋出異常 4.1 自定義異常拋出 4.2 創建自定義異常類 …

基于混沌映射的LDPC信道編譯碼matlab性能仿真,對比LDPC

目錄 1.算法仿真效果 2.算法涉及理論知識概要 2.1 混沌映射 2.2 基于混沌映射的LDPC編譯碼 3.MATLAB核心程序 4.完整算法代碼文件獲得 1.算法仿真效果 matlab2022a仿真結果如下(完整代碼運行后無水印): 仿真操作步驟可參考程序配套的操…