數據結構課程設計------c實現散列表(二次探測再哈希)電話簿(文件存儲)

題目二 :散列表的設計與實現

2.1問題描述

設計散列表實現電話號碼查找系統,使得平均查找長度不超過2

基本要求
(1)設每個記錄有下列數據項:電話號碼、用戶名、地址;
(2)從鍵盤輸入各記錄,以電話號碼為關鍵字建立散列表;
(3)采用一定的方法解決沖突;
(4)查找并顯示給定電話號碼的記錄;

2.2.算法設計與分析

2.2.1設計思路分析
基本思路
1構建哈希表(需要構造一個哈希函數,確定一個合適的處理沖突的方法)
2按照電話號碼查找并輸出
3將哈希表按序存進文件中
基本思想
1 哈希表是根據關鍵碼而直接進行訪問的數據結構,也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數叫做散列函數,存放記錄的數組叫做散列表
2給定表M,存在函數f(key),對任意給定的關鍵子值key,代入函數后能得到包含該關鍵字的記錄在表中的地址,則稱表M為哈希表,函數f(key)為哈希函數。
3 二次探測再散列法:若發生沖突,則按照+12,-12,+22,-22……方式進行探測再散列的方法。

2.2.2設計程序流程圖
在這里插入圖片描述
進入程序,進行功能選擇,選擇1進行存入電話號碼,構建哈希表,如果存在沖突解決沖突再錄入,不存在直接錄入信息。選擇0查找電話號碼,怎么解決沖突,就按相應的方法查找。所有功能執行完后返回,選擇0退出程序,程序結束。
2.2.3數據結構定義

typedef struct record				//定義一條記錄的結構體
{char Number[20];				char Name[20];char Address[20];
}Record;typedef struct Hash					//定義一個散列表
{Record *data;					//存訪多條記錄的數組int cnt;						int size;						//數組大小
}*HashTable, HashElem;

2.2.4算法的時間復雜度分析
整個程序的時間復雜度看哈希表在解決沖突時的時間復雜度
解決沖突
最差的時間復雜度O(n),當所有數據被填滿時
最好的時間復雜度O(1)沒有沖突的時候.

2.3源程序清單

hash.h文件

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>#define MAXSIZE 50using namespace std;				typedef struct record				//定義一條記錄的結構體
{char Number[20];				char Name[20];char Address[20];
}Record;typedef struct Hash					//定義一個散列表
{Record *data;					//存訪多條記錄的數組int cnt;						int size;						//數組大小
}*HashTable, HashElem;void savenumb(HashTable numbertable, Record record[]);		//存訪函數
void findnumb(HashTable numbertable);						//查詢函數

function.cpp文件

#define _CRT_SECURE_NO_WARNINGS
#include"hash.h"int Czy = 1;
//哈希函數,將電話號碼每一位求和 
int GetHashKey(char ar[])
{int len = strlen(ar);						//計算電話號碼的長度int key = 0;for (int i = 0; i<len; i++){					key += ar[i] - '0';						//key=總和,數字字符減'0'就是數字}return key%MAXSIZE;//必須取模,否則下標越界		//返回得到的地址
}//沖突處理,二次探測再散列 
int HandleCollision(HashTable table, int key)
{Czy = 1; //從2,3,4,5,....... while (1){Czy++; //從2,3,4,5,....... if (Czy % 2 == 0) {										//偶數和偶數下一個數奇數除二的值相等if (table->data[(key + (Czy / 2)*(Czy / 2)) % MAXSIZE].Name[0] == 0)	//這個位置上沒有數據	return (key + (Czy / 2)*(Czy / 2)) % MAXSIZE;						//返回這個位置上的地址}else if (Czy % 2 != 0) {if ((key - (Czy / 2)*(Czy / 2))<0) continue;                             //由于是減法,要注意負數不能取模 if (table->data[(key - (Czy / 2)*(Czy / 2)) % MAXSIZE].Name[0] == 0)	//如果這個位置上沒有數據return (key - (Czy / 2)*(Czy / 2)) % MAXSIZE;}}//return -1;
}//構建哈希表 
void CreateHashTable(HashTable &table, Record *record, int n)
{int key;for (int i = 0; i<n; i++){key = GetHashKey(record[i].Number);				//接受每個電話返回來的地址if (table->data[key].Name[0] != 0)				//當這個地址里的名字不為空時,也就是有沖突了key = HandleCollision(table, key);			//進行沖突處理  傳沖突的地址//如果不沖突,則進行賦值strcpy(table->data[key].Number, record[i].Number);	strcpy(table->data[key].Name, record[i].Name);strcpy(table->data[key].Address, record[i].Address);}
}//按照電話號碼尋找 
int SerchKey(HashTable table, char PhoneNumber[])
{int key = GetHashKey(PhoneNumber);						//得到該元素的最初地址位置if (strcmp(table->data[key].Number, PhoneNumber)){		//如果該位置上的數與給定的數不相等,則考慮沖突尋址for (Czy = 1; Czy < MAXSIZE; Czy++){if (Czy % 2 == 0) {//strcmp(str1,str2)//當str1的字典序大于str2時返回一個一個正數 小于負數,等于0if (!strcmp(PhoneNumber, table->data[(key + (Czy / 2)*(Czy / 2)) % MAXSIZE].Number)){//如果相等則地址就等于沖突處理后的值key = (key + (Czy / 2)*(Czy / 2)) % MAXSIZE;break;}}else if (Czy % 2 != 0) {if ((key - (Czy / 2)*(Czy / 2)) < 0) continue;//由于是減法,要注意負數不能取模			//如果取差后為負數,則不做處理,Czy+1//不是負數,判斷值是否與當前地址值相等if (!strcmp(PhoneNumber, table->data[(key - (Czy / 2)*(Czy / 2)) % MAXSIZE].Number)){key = (key - (Czy / 2)*(Czy / 2)) % MAXSIZE;break;}}}}return key;
}
//將哈希表存入文件中 void GoToFile(HashTable table)
{FILE *fp = fopen("Output.txt", "w");				//打開文件Output.txtfor (int i = 0; i <= MAXSIZE; i++)					//遍歷整個散列表if (table->data[i].Name[0] != 0)					//如果名字不為空,則寫入文件fprintf(fp, "%s %s %s\n", table->data[i].Name, table->data[i].Number, table->data[i].Address);//printf("%s %s %s\n",table->data[i].Name,table->data[i].Number,table->data[i].Address);	fclose(fp);											//關閉文件
}void findnumb(HashTable numbertable){				//查詢函數int key = 0;//輸入并尋找PhoneNumber(必須存在表中) char PhoneNumber[20];printf("請輸入你想找的電話:\n");cin >> PhoneNumber;cout << "給定電話號碼為:" << endl << PhoneNumber << endl;key= SerchKey(numbertable, PhoneNumber);if (!strcmp(numbertable->data[key].Number, PhoneNumber)){printf("找到的電話信息為:\n");}else{printf("\n沒有該電話號碼\n");return;}cout << numbertable->data[key].Name << " " << numbertable->data[key].Number << " " << numbertable->data[key].Address << endl;}void savenumb(HashTable numbertable,Record record[]){			//保存函數int k;//輸入數據 組數及 各個數據 //freopen("Data.txt","r",stdin);printf("你想要存入幾個人的電話\n");cin >> k;while(k > 10){printf("一次至多只能存放10人\n");printf("請重新輸入:\n");cin >> k;}for (int i = 0; i < k; i++){printf("請輸入電話\n");cin >> record[i].Number;printf("請輸入姓名\n");cin >> record[i].Name;printf("請輸入住址\n");cin >> record[i].Address;}//創建哈希表 CreateHashTable(numbertable, record, k);//存入文件中 GoToFile(numbertable);printf("保存成功\n");}

Main.cpp文件

#include"hash.h"
void menu2(){printf("****************************\n");printf("*歡迎使用電話簿(散列表版本)*\n");printf("****** 1存入電話號碼 *******\n");printf("****** 2查找電話號碼 *******\n");printf("****** 0 退出程序    *******\n");printf("****************************\n");
}void menu(){//定義及初始化 Record record[50];			//定義結構體數組,可以存放50個元素的信息HashElem table;				//散列表結構體變量HashTable numbertable;		//散列表結構體指針numbertable = &table;		//給結構體指針賦初值numbertable->data = (Record*)malloc(sizeof(record[0])*MAXSIZE);memset(numbertable->data, 0, sizeof(record[0])*MAXSIZE);numbertable->size = MAXSIZE;numbertable->cnt = 0;int input;do{menu2();printf("請輸入你想要執行的操作\n");scanf("%d", &input);switch (input){case 1:savenumb(numbertable, record);break;case 2:findnumb(numbertable);break;case 0:printf("再見\n");break;default:printf("你的輸入有誤請重新輸入\n");break;}} while (input);}int main(){menu();system("pause");return 0;
}

2.4執行結果

1存入電話號碼

在這里插入圖片描述

2查找電話號碼

在這里插入圖片描述
0退出程序
在這里插入圖片描述

2.5存在問題分析

  1. 電話簿中無法分辨電話相同的情況。
    2 電話簿沒有一個圖形化界面,用戶需要手動輸入相關命令,無法實現鼠標點擊

2.6結論

基本實現了電話簿的添加和查找功能

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

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

相關文章

科技論文----論搜索引擎現狀及發展趨勢

搜索引擎現狀及發展趨勢 【摘要】 隨著最近10年中國互聯網的快速發展菜互聯網已經徹底改變了人們的生活方式&#xff0c;而在互聯網的發展過程中。搜索引擎發揮了巨大的推動作用。本文對搜索引擎的發展歷史采用的技術&#xff0c;發展現狀出現的問題以及未來發展方向進行了綜述…

inittab文件格式

/etc/inittab文件是Linux系統第一個進程init的配置文件。其每個記錄占一行&#xff0c;每行最多512個字符。該文件的每個記錄的格式為&#xff1a; id:runlevel:action:process 其中&#xff0c;id是一個不超過4個字符的標識&#xff0c;用來唯一標識一條記錄。runlevel表明該條…

數據結構課程設計------掃雷游戲(升級版,可展開)

本程序由團隊中的一個人所寫&#xff0c;本人看懂并寫下此文章 題目&#xff1a;掃雷 3.1問題描述 掃雷游戲 [基本要求] &#xff08;1&#xff09;完成棋盤的初始化并在標準顯示器中顯示 &#xff08;2&#xff09;通過輸入行列值確定用戶輸入 &#xff08;3&#xff09;游…

C語言的編譯鏈接過程的介紹

發布時間: 2012-11-08 10:17 作者: 未知 來源: 51Testing軟件測試網采編 字體: 小 中 大 | 上一篇 下一篇 | 打印 | 我要投稿 | 推薦標簽&#xff1a; DotNet 軟件開發 | 感言十年 C語言的編譯鏈接過程要把我們編寫的一個c程序&#xff08;源代碼&#x…

vs2013鏈接Mysql時出現 (由于找不到libmysql.dll,無法繼續執行代碼。重新安裝程序可能會解決此問題)

將MySQL安裝目錄下的lib文件夾中 的libmysql.dll文件拷貝到C:\Windows\System32目錄下即可

gcc 優化選項 -O1 -O2 -O3 -Os 優先級,-fomit-frame-pointer

少優化->多優化&#xff1a; O0 -->> O1 -->> O2 -->> O3 -O0表示沒有優化,-O1為缺省值&#xff0c;-O3優化級別最高 英文解析&#xff1a; -O -O1 Optimize. Optimizing compilation takes somewhat more time, an…

const 和 #define 區別總結

const有類型&#xff0c;可進行編譯器安全檢查&#xff0c;#define 無類型&#xff0c;不可進行類型檢查const 有作用域&#xff0c;而#define 不重視作用域&#xff0c;默認定義在指定作用域下有效的常量&#xff0c;那么#define 就不能用&#xff08;可以用#undef結束宏定義生…

Eclipse : Unresolved inclusion

Eclipse 中新建C 或C 到項目時&#xff0c;頭文件報警&#xff0c;顯示“Unresolved inclusion:<stdio.h>” 雖然不影響項目到編譯和運行&#xff0c;確也無法查看頭文件&#xff0c;讓人感覺實在不爽。下面是在國外到網站上看到解決方案&#xff0c;自己整理了一下拿來分…

c++對const增強 和cosnt分配內存情況

const增強 c語言中const是偽常量&#xff0c;可以通過指針修改 c中const會放到符號表中 c語言中const默認是外部連接&#xff0c;c中const默認是內部鏈接 #include<iostream> using namespace std;const int m_a 10; //在全局區域里&#xff0c;受到保護&…

Linux下crontab命令的用法

任務調度的crond常駐命令 crond 是linux用來定期執行程序的命令。當安裝完成操作系統之后&#xff0c;默認便會啟動此任務調度命令。crond命令每分鍾會定期檢查是否有要執行的工作&#xff0c;如果有要執行的工作便會自動執行該工作。而linux任務調度的工作主要分為以下兩類&am…

c++中引用的作用

引用的基本語法 用途起別名 Type &別名原名 引用必須初始化 一旦初始化后&#xff0c;不能修改 對數組建立引用 #include<iostream>using namespace std;//1.引用基本語法 Type &別名原名void test01(){int a 10;int &b a;cout << "a"…

LVM (Logic Volume Management,邏輯卷管理)

是傳統商業Unix就帶有的一項高級磁盤管理工具&#xff0c;異常強大。后來LVM移植到了Linux操作系統上&#xff0c;盡管不像原來Unix版本那么強大&#xff0c;但瘦死的駱駝比馬大&#xff0c;Linux的LVM仍然非常強大&#xff0c;可以在生產運行系統上面直接在線擴展硬盤分區&…

cpu中的MMU的作用

虛擬內存與物理內存之間的映射 用戶空間映射到物理內存是獨立的&#xff0c;提高安全性修改內存訪問級別 &#xff08;0是最高級&#xff09;

Linux命令行與Shell腳本編程大全讀書筆記

Linux內核4大主要功能&#xff1a; 內存管理 進程管理 設備管理 文件系統管理 Linux系統啟動的進程和腳本管理 1./etc/inittab 管理系統開機時會自動啟動的進程 2./etc/init.d 管理開機時啟動或停止某個應用的腳本放在這個目錄下&#xff0c;/etc/rcX.d目錄在啟動時&…

拷貝構造函數的總結

構造函數的分類及調用 按照參數分類 1.無參構造&#xff08;默認構造&#xff09; 2.有參構造按照類型分類 1.普通構造函數2.拷貝構造函數無參構造寫法和調用 Person p1; 注意不能寫Person (),因為編譯器認為這個是函數聲明有參構造函數寫法 和調用 Person p2(10) 或者Per…

技術與技巧札記

Linux常用命令及技巧&#xff1a; &#xff08;1&#xff09;cat /proc/version 查看當前內核的版本 (2) 掛載nfs文件夾&#xff1a;需要先確認在&#xff0f;etc&#xff0f;exports文件&#xff0c;可以用于開發板掛載的文件夾 mount -o nolock 10.0.22.30:/root/sharednfs …

c++中new的總結(動態管理,malloc存在的問題,malloc與new的區別)

c中使用malloc出現的問題 程序員必須確定對象的長度malloc 返回一個&#xff08;void *&#xff09;指針 &#xff0c;c不允許將&#xff08;void*) 賦值給其它指針&#xff0c;必須強轉malloc可能申請內存失敗&#xff0c;所以必須判斷返回值來保存內存分配成功用戶在使用對象…

Linux中變量#,@,0,1,2,*,$$,$?的含義

$# 是傳給腳本的參數個數 $0 是腳本本身的名字 $1 是傳遞給該shell腳本的第一個參數 $2 是傳遞給該shell腳本的第二個參數 $ 是傳給腳本的所有參數的列表 $* 是以一個單字符串顯示所有向腳本傳遞的參數&#xff0c;與位置變量不同&#xff0c;參數可超過9個 $$ 是腳本運行的當前…

Volatile的陷阱

最近寫的關于在嵌入式開發中常遇到的關于volatile關鍵字使用的短文&#xff0c;都是些通用的技術&#xff0c;貼上來share。 對于volatile關鍵字&#xff0c;大部分的C語言教材都是一筆帶過&#xff0c;并沒有做太過深入的分析&#xff0c;所以這里簡單整理了一些關于volatile的…

c++中靜態成員變量和靜態成員函數

靜態成員變量 在一個類中&#xff0c;若將一個成員變量聲明為static,這種成員成為靜態成員變量&#xff0c;與一般的數據成員不同&#xff0c;無論建立了多少個對象&#xff0c;都只想有一個靜態數據的拷貝&#xff0c;靜態成員變量&#xff0c;屬于某個類&#xff0c;所有對象…