数据结构 C++实现 基于不同策略的英文单词的词频统计和检索系统(糅合版)
生活随笔
收集整理的這篇文章主要介紹了
数据结构 C++实现 基于不同策略的英文单词的词频统计和检索系统(糅合版)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 一、實驗目的
- 二、設計內容
- 三、測試數據
- 四、設計思路
- 五、代碼內容
- 1、函數運行時間(高精度)
- 2、函數運行時間(低精度)
- 3、代碼實現
- 六、運行結果
- 七、總結
一、實驗目的
1、掌握基于線性表、二叉排序樹和散列表不同存儲結構的查找算法。
2、掌握不同檢索策略對應的平均查找長度(ASL)的計算方法,明確不同檢索策略的時間性能的差別。
二、設計內容
一篇英文文章存儲在一個文本文件中,然后分別基于線性表、二叉排序樹和哈希表不同的存儲結構,完成單詞詞頻的統計和單詞的檢索功能。同時計算不同檢索策略下的平均查找長度ASL,通過比較ASL的大小,對不同檢索策略的時間性能做出相應的比較分析(比較分析要寫在實習報告中的“收獲和體會”中)。
(1)詞頻統計
當讀取一個單詞后,若該單詞還未出現,則在適當的位置上添加該單詞,將其詞頻計為1;若該單詞已經出現過,則將其詞頻增加1。統計結束后,將所有單詞及其頻率按照詞典順序寫入文本文件中。其中,不同的檢索策略分別寫入6個不同的文件。
基于順序表的順序查找— OutFile1.txt
基于鏈表的順序查找— OutFile2.txt
折半查找— OutFile3.txt
基于二叉排序樹的查找— OutFile4.txt
基于開放地址法的哈希查找— OutFile5.txt
基于鏈地址法的哈希查找— OutFile6.txt
注:如果實現方法正確,6個文件的內容應該是一致的。
(2)單詞檢索
輸入一個單詞,如果查找成功,則輸出該單詞對應的頻率,同時輸出查找成功的平均查找長度ASL和輸出查找所花費的時間。如果查找失敗,則輸出“查找失敗”的提示。
三、測試數據
我這里只是隨便找的比較短的一篇
四、設計思路
五、代碼內容
點擊這里有分塊寫的代碼
1、函數運行時間(高精度)
精度比較高
#include<iostream> #include<thread> using namespace std ; using namespace chrono; //使用命名空間chrono template <typename T> //函數模板/* 關鍵詞 auto 看上去很高大上,它是一個“自動類型”,可以理解成“萬能類型”,想成為啥,就成為啥 system_clock 是 C++11 提供的一個 clock。除此之外,還有兩個clock:steady_clock 和 high_resolution_clock clock:時鐘 now( ) 表示計時的那“一瞬間” duration_cast< > 表示類型轉換 duration:持續時間 count( ) 用來返回時間 */ void measure(T&& func) {auto start = system_clock::now(); //開始時間func(); //執行函數duration<double> diff = system_clock::now() - start; //現在時間 - 開始時間cout << "elapsed: " << diff.count() << "秒" << endl; }void func(){long long s = 0;for(int i=0;i<20000000;i++){s+=i;}cout<<s<<endl; } int main(){measure(func);return 0; }2、函數運行時間(低精度)
精度比較低
#include <ctime> #include <iostream> using namespace std;void func(){long long s = 0;for(int i=0;i<20000000;i++){s+=i;}cout<<s<<endl; } int main(){clock_t start = clock();func();clock_t end = clock();cout << "花費了" << (double)(end - start) / CLOCKS_PER_SEC << "秒" << endl; }3、代碼實現
//寫一個標準的頭文件避免重復編譯 #ifndef _HEAD_H #define _HEAD_H/*#include <fstream>ofstream //文件寫操作 內存寫入存儲設備ifstream //文件讀操作,存儲設備讀取到內存中fstream //讀寫操作,對打開的文件可進行讀寫操作void open(const char* filename,int mode,int access);參數:filename: 要打開的文件名mode: 要打開文件的方式access: 打開文件的屬性打開文件的方式在類ios(是所有流式I/O類的基類)中定義.常用的值如下:ios::app: 以追加的方式打開文件ios::ate: 文件打開后定位到文件尾,ios:app就包含有此屬性ios::binary: 以二進制方式打開文件,缺省的方式是文本方式。兩種方式的區別見前文ios::in: 文件以輸入方式打開(文件數據輸入到內存)ios::out: 文件以輸出方式打開(內存數據輸出到文件)ios::nocreate: 不建立文件,所以文件不存在時打開失敗ios::noreplace:不覆蓋文件,所以打開文件時如果文件存在失敗ios::trunc: 如果文件存在,把文件長度設為0 */#include<iostream> #include<thread> #include<fstream> #include<string> #include<ctime> #include<cmath> #include<Windows.h> using namespace std; using namespace chrono; //使用命名空間chrono//常量 const int MaxSize = 1000; //文章單詞最大容量 const char* file = "file.txt"; //待檢索文件 static int sum = 0; //單詞總數(不重復)// 結構體// 詞頻順序存儲結構 struct WordFrequency { //詞頻string word; //單詞int frequency; //頻率int key; //關鍵碼 }WF[MaxSize];typedef WordFrequency datatype; //為數據類型定義一個新的名字//詞頻鏈式存儲結構 struct Node {datatype data; //數據域Node* next; //指針域 };//二叉排序樹鏈式存儲結構 struct BiNode {datatype data; //節點數據域BiNode* lchild, * rchild; //左右孩子指針 };//ReadFile函數聲明 int StatisticalWord(string word); //統計文章詞頻(去掉重復單詞) string WordTransition(string word); //大寫英語單詞轉化成小寫 int WordJudge(string word); //判斷單詞中是否有大寫字母 void StatisticsData(); //數據統計 int WordTransitionKey(string word); //將單詞轉換為唯一關鍵碼//LinkedListMenu函數聲明 void ListMenu(); // 線性表菜單 void SequenceMenu(); //順序查找菜單 void SeqListMenu(); //順序表順序查找菜單 void WorLocatMenu();//順序表單詞查找菜單 void LinklistSeqMenu();//鏈表順序查找菜單 void LinklistLocateMenu(); //鏈表單詞查找菜單 void HalfSortMenu(); //順序表折半查找菜單 void HalfdLocateMenu(); //順序表折半單詞查找菜單//BiTreeMenu函數聲明 void BiTreeMenu(); // 二叉排序樹菜單 void BitreeLocateMenu(); //二叉排序樹的順序查找菜單 void BitreeWordLocMenu(); //二叉排序樹查找單詞菜單//HashTableMenu函數聲明 void HashMenu(); //哈希表菜單 void OpenHashLocateMenu(); //開放地址法哈希查找菜單 void OpenHashLocate(); //開放地址法哈希查找 void LinkHashLocate(); //鏈地址法哈希查找 void LinkHashWordLocateMenu(); //開放地址法哈希查找菜單void MajorMenu(); //主菜單#endif // !_HEAD_H//主函數 int main(){ifstream fin;fin.open(file);//關聯文件fileif (!fin.is_open()){cout << "file.txt文件不存在,請檢查文件名或者目錄下文件是否存在。" << endl;system("pause"); //暫停return 0;} //ifelse{cout << "file.txt文件加載中..." << endl;Sleep(1000);//延時1秒} //elseStatisticsData(); //數據統計MajorMenu();//主菜單return 0; }//主菜單 void MajorMenu(){while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---菜單---" << endl;cout << "1.基于線性表的查找" << endl;cout << "2.基于二叉排序樹的查找" << endl;cout << "3.基于哈希表的查找" << endl;cout << "4.退出系統" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1: ListMenu();break;case 2:BiTreeMenu();break;case 3:HashMenu(); break;case 4: cout << "系統已退出" << endl; return;default: cout << "輸入的不是有效符號,請重新輸入" << endl; system("cls"); //清屏system("pause"); //暫停} //switch} //for }// 讀取TXT內容并整理 //統計文章詞頻(去掉重復單詞) int StatisticalWord(string word){for (int i = 0; i < MaxSize; i++){ //循環控制,單詞查重if (WF[i].word == word){ //單詞重復WF[i].frequency++; //詞頻+1return i; //退出函數} //if} //for//單詞不重復WF[sum].word = word; //添加單詞WF[sum].frequency = 1; //詞頻置為一WF[sum].key = WordTransitionKey(word); //添加關鍵碼sum ++; //單詞總數+1return 0; }//大寫英語單詞轉化成小寫 string WordTransition(string word){for (int i = 0; i < int(word.size()); i++){ //獲取字符串長度,使用length()也可以if (word[i] >= 'A' && word[i] <= 'Z') //判斷字符是否是大寫字母word[i] = word[i] + 32; //ASCII碼表中十進制 A==65 a==97 中間相差32,后面的也是如此} //forreturn word; //返回小寫單詞 }//判斷單詞中是否有大寫字母 int WordJudge(string word){for (int i = 0; i < int(word.size()); i++){if (word[i] >= 'A' && word[i] <= 'Z') //判斷單詞中是否有大寫字母return 1; //如果有,返回1} //forreturn 0; //沒有返回0 }//詞頻統計 void StatisticsData(){system("cls"); //清屏ifstream fin; //文件讀操作,存儲設備讀取到內存中fin.open(file); //關聯文件filechar ch; //用于獲取字符 string word; //用于存放單詞int count = 0,min; //count用于標記單詞個數,min用于標記最小的單詞for (int i = 0; fin.get(ch); i++){ //讀取文件內容,并去除符號if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')){if (word == "\0") //word為空,放入第一個字母word = ch;elseword += ch; //word不為空,拼接字母組成單詞} //ifelse{if (word != "\0"){ //判斷之前的word里面是否有單詞count++; //有單詞,總數+1if (count > MaxSize){cout << "文章單詞超出統計上限,系統已退出" << endl;fin.close(); //關閉文件exit(0); //退出程序system("pause"); //暫停}StatisticalWord(word); //存放到結構體數組里面} //ifword = "\0"; //重置word,用于存放新單詞} //else} //for//按照詞典排序(選擇排序) 從小到大WordFrequency temp; //臨時存儲空間for (int i = 0; i < sum; i++){min = i; //重置minfor (int j = i + 1; j < sum; j++){if (WordTransition(WF[j].word) < WordTransition(WF[min].word)) //將單詞轉換成小寫進行比較min = j; //得到最小單詞序號} //for//交換原始單詞,詞頻temp = WF[i];WF[i] = WF[min];WF[min] = temp;} //forfor (int i = 0; i < sum; i++){min = i;for (int j = i + 1; j < sum; j++){if (WordTransition(WF[j].word) == WordTransition(WF[min].word)) //兩個單詞相等if (WordJudge(WF[j].word) > WordJudge(WF[min].word)) //大寫的排前面min = j; //得到最小單詞序號} //for//交換原始單詞,詞頻temp = WF[i];WF[i] = WF[min];WF[min] = temp;} //forfin.close(); //關閉文件 }//將單詞轉換為唯一關鍵碼 int WordTransitionKey(string word) {int a[21] = { 0,2,3,5,7,11,13,17,19,23,27,29,31,37,41,47,51,67,87,101,111 }; //最長識別20個字母的的單詞int sumkey = 0;for (int i = 0; i < int(word.size()); i++) {sumkey += int(word[i]); //每個字符的ASCLL值相加}sumkey += int('h') * a[int(word.size())];return sumkey; }//順序表類 class SeqList{public:SeqList() {} //無參構造SeqList(datatype a[], int n){ //有參構造函數,初始化長度為n的順序表if (n > MaxSize){cout << "單詞數量過多,超出線性表最大容量" << endl;} //iffor (int i = 0; i < n; i++){wf[i].word = a[i].word;wf[i].frequency = a[i].frequency;} //for}~SeqList(){}; //析構函數int Empty(); //順序表判空函數void PrintList(int n); //遍歷操作,按序號依次輸出各元素int SeqlistLocate(string word); //順序查找int BinSearch(string word); //折半查找string getword(int n); //返回單詞int getfre(int n); //返回詞頻private:datatype wf[MaxSize]; //存放詞頻結構體的數組 };//返回單詞 string SeqList::getword(int n) {return wf[n].word; }//返回詞頻 int SeqList::getfre(int n) {return wf[n].frequency; }//順序表判空函數 int SeqList::Empty(){if (sum == 0)return 1;elsereturn 0; }//順序查找 int SeqList::SeqlistLocate(string word){for (int i = 0; i < sum; i++){ //依次遍歷if (wf[i].word == word) //找到wordreturn i; //返回下標} //forreturn -1; //未找到返回-1 }//折半查找 int SeqList::BinSearch(string word){int mid, low = 0, high = sum - 1; //初始查找區間是[0, sum-1]while (low <= high) { //當區間存在時mid = (low + high) / 2; //初始化中值if (word == wf[mid].word) //找到wordbreak; //退出循環else if (WordTransition(word) < WordTransition(wf[mid].word)) //word在前半段high = mid - 1; //改變上限,gigh前移查找區間變為 [low,mid-1]else //word在后半段,或者不存在low = mid + 1; //改變下線,low后移查找區間變為 [mid+1,high]} //whileif (low <= high)return mid; //找到返回下標elsereturn -1; //未找到返回-1 }//輸出線性表順序表,參數n用來控制輸出順序查找還是折半查找 void SeqList::PrintList(int n){system("cls"); //清屏if (n == 1){ofstream fout; //文件寫操作 內存寫入存儲設備 fout.open("outfile1.txt");fout << "單詞總數為:" << sum << endl;fout << "詞頻" << "\t" << "單詞" << endl;for (int i = 0; i< sum; i++){fout << wf[i].frequency << "\t" << wf[i].word << endl; } //forfout.close(); //關閉文件} //ifif (n == 2){ofstream fout; //文件寫操作 內存寫入存儲設備 fout.open("outfile3.txt");fout << "單詞總數為:" << sum << endl;fout << "詞頻" << "\t" << "單詞" << endl;for (int i = 0; i < sum; i++) {fout << wf[i].frequency << "\t" << wf[i].word << endl;} //forfout.close(); //關閉文件} //ifcout << "單詞總數為:" << sum << endl;cout << "詞頻" << "\t" << "單詞" << endl;for (int i = 0; i < sum; i++)cout << wf[i].frequency << "\t" << wf[i].word << endl;if (n == 1)cout << "單詞以及詞頻已經保存到文件outfile1.txt文件中" << endl;else if (n == 2)cout << "單詞以及詞頻已經保存到文件outfile3.txt文件中" << endl;system("pause"); //暫停 }//鏈表類 class LinkList{public:LinkList(datatype a[], int n) { //有參構造函數,建立有n個元素的單鏈表Head = new Node; //生成頭結點Node* r = Head, * s = NULL; //尾指針初始化,并定義存儲指針for (int i = 0; i < n; i++){s = new Node; s->data = a[i]; //數據域賦值r->next = s; //將存儲節點s插入鏈表r = s; //更新尾指針} //forr->next = NULL; //單鏈表建立完畢,將終端結點的指針域置空}~LinkList() { //析構函數Node* temp = NULL; //定義臨時節點while (Head != NULL){ //釋放單鏈表的每一個結點的存儲空間temp = Head; //暫存被釋放結點Head = Head->next; // Head指向被釋放結點的下一個結點delete temp;} //while}int Empety(); //判斷鏈表是否為空int Locate(string word); //按值查找,返回下標void PrintList(); //遍歷操作,按序號依次輸出各元素datatype getdata(int n);private:Node* Head; //單鏈表的頭指針 };//返回數據域 datatype LinkList::getdata(int n) {Node* t = Head->next; //指針初始化for (int i = 1; i < n; i++)t = t->next;return t->data;}//判空 int LinkList::Empety(){if (Head->next)return 1; //鏈表非空,正常返回return 0; //鏈表為空,返回-1 }//輸出單鏈表 void LinkList::PrintList(){system("cls"); //清屏Node* p = Head->next;//工作指針p初始化ofstream fout; //文件寫操作 內存寫入存儲設備 fout.open("outfile2.txt"); //打開文件fout << "單詞總數為:" << sum << endl;fout << "詞頻" << "\t" << "單詞" << endl;while (p != NULL){fout << p->data.frequency << "\t" << p->data.word << endl;p = p->next; //指針p后移} //whilefout.close(); //關閉文件cout << "單詞總數為:" << sum << endl;cout << "詞頻" << "\t" << "單詞" << endl;Node* p1 = Head->next;//工作指針p初始化while (p1){ //p <--> p != NULLcout << p1->data.frequency << "\t" << p1->data.word << endl;p1 = p1->next; //工作指針p后移,注意不能寫作p++} //whilecout << "單詞以及詞頻已經保存到文件outfile2.txt文件中" << endl;system("pause"); //暫停 }//按值查找,返回下標 int LinkList::Locate(string word){Node* p = Head->next; //指針p初始化int count = 1; //計數器count初始化,表示查找次數while (p != NULL){if (p->data.word == word) return count; //查找成功,結束函數并返回下標p = p->next; //p指針后移count++;} //whilereturn -1; //退出循環表明查找失敗 }// 線性表菜單 void ListMenu(){while(true) {system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---基于線性表的查找---" << endl;cout << "1.順序查找" << endl;cout << "2.折半查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1 : SequenceMenu(); //順序查找菜單break;case 2 : HalfSortMenu(); //順序表折半查找菜單break;case 3 : return; //結束函數default: cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause"); //暫停} //switch} //while }//順序查找菜單 void SequenceMenu(){while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---順序查找---" << endl;cout << "1.順序表查找" << endl;cout << "2.鏈表順序查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1:SeqListMenu(); //順序查找菜單break;case 2: LinklistSeqMenu(); //鏈表查找菜單break;case 3: return; //結束函數default:cout << "輸入的不是有效符號,請重新輸入" << endl;system("pause"); //暫停break;} //switch} //while }//順序表順序查找菜單 void SeqListMenu(){SeqList L(WF, sum);while(true){system("cls");cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---順序表順序查找---" << endl;cout << "1.詞頻統計" << endl;cout << "2.單詞查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1: L.PrintList(1); //輸出線性表順序表詞頻統計break;case 2: WorLocatMenu(); //順序表順序單詞查找菜單break;case 3:return;default: cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause");} //switch} //whilereturn; }//鏈表順序查找菜單 void LinklistSeqMenu(){LinkList L(WF, sum);while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---鏈表順序查找---" << endl;cout << "1.詞頻統計" << endl;cout << "2.單詞查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1: L.PrintList(); //輸出線性表鏈表詞頻統計break;case 2:LinklistLocateMenu(); //鏈表單詞查找break;case 3: return;default:cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause"); //暫停} //switch} //whilereturn; }//順序表順序單詞查找菜單 void WorLocatMenu(){SeqList L(WF , sum); system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---順序表單詞查找---" << endl;cout << "請輸入要查找的單詞:";string word;cin >> word; //鍵盤錄入要查找單詞auto start = system_clock::now(); //開始時間int i = L.SeqlistLocate(word); //返回下標duration<double> diff = system_clock::now() - start; //現在時間 - 開始時間if (i+1) {cout << "此單詞為:" << L.getword(i) << endl;cout << "此單詞的詞頻:" << L.getfre(i) << endl;cout << "查找該單詞所花費的時間:" << (diff.count())*1000 << "毫秒" << endl;cout << "平均查找長度:" << (sum + 1) / 2 << endl;} //ifelsecout << "查找失敗" << endl;system("pause"); //暫停 }//鏈表單詞查找菜單 void LinklistLocateMenu(){LinkList L(WF, sum);system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---鏈表單詞查找---" << endl;cout << "請輸入要查找的單詞:";string word;cin >> word;auto start = system_clock::now(); //開始時間int i = L.Locate(word);duration<double> diff = system_clock::now() - start; //現在時間 - 開始時間if (i) {cout << "此單詞為:" << L.getdata(i).word << endl;cout << "此單詞的詞頻:" << L.getdata(i).frequency << endl;cout << "查找該單詞所花費的時間:" << (diff.count())*1000 << "毫秒" << endl;cout << "平均查找長度:" << (sum + 1) / 2 << endl;} //ifelsecout << "查找失敗" << endl;system("pause"); //暫停 }//順序表折半查找菜單 void HalfSortMenu(){SeqList L(WF, sum);while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---基于順序表的折半查找---" << endl;cout << "1.詞頻統計" << endl;cout << "2.單詞查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1:L.PrintList(2); //折半查找,輸出break;case 2: HalfdLocateMenu(); //折半查找break;case 3:return; //退出函數default: cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause"); //暫停} //switch} //while }//順序表折半查找菜單 void HalfdLocateMenu(){SeqList L(WF, sum);system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---折半單詞查找---" << endl;cout << "請輸入要查找的單詞:";string word;cin >> word;auto start = system_clock::now(); //開始時間L.BinSearch(word);duration<double> diff = system_clock::now() - start; //現在時間 - 開始時間int i = L.BinSearch(word); //返回下標if (i >= 0) {cout << "此單詞為:" << L.getword(i) << endl;cout << "此單詞的詞頻:" << L.getfre(i) << endl;cout << "查找該單詞所花費的時間:" << (diff.count())*1000 << "毫秒" << endl;cout << "平均查找長度:" << double((log(double(sum) + 1) / log(2)) - 1) << endl;} //ifelsecout << "查找失敗" << endl;system("pause"); //暫停 }//開放地址哈希表類 class HashTable{public:HashTable(); //構造函數,初始化空散列表~HashTable(){}; //析構函數int Insert(datatype a); //插入int Search(string word); //查找datatype Get(int a);void Print(); //輸出private:int H(int k); //哈希函數(散列函數)datatype ht[MaxSize]; //散列表 };//構造函數 HashTable::HashTable(){for (int i = 0; i < MaxSize; i++){ht[i].key = 0; //關鍵碼初始化ht[i].word = "";ht[i].frequency = 0; // 0表示該散列單元為空} //for }//哈希函數,除留余數法 int HashTable::H(int k){return k % MaxSize; }//輸出函數 void HashTable::Print() {system("cls"); //清屏ofstream fout; //文件寫操作 內存寫入存儲設備fout.open("outfile5.txt"); //打開文件fout << "單詞總數為:" << sum << endl;fout << "詞頻" << "\t" << "單詞" << endl;for (int i = 0; i < sum; i++) {fout << WF[i].frequency << "\t" << WF[i].word << endl;cout << WF[i].frequency << "\t" <<WF[i].word << endl;} //forsystem("pause"); //暫停 }//查找函數 int HashTable::Search(string word){int key = WordTransitionKey(word); //將單詞轉化為關鍵碼int i = H(key); //計算散列地址,設置比較的起始位置while (ht[i].key != 0){if (ht[i].word == word) return i; //查找成功else i = (i + 1) % MaxSize; //向后探測一個位置} //whilereturn 0; //查找失敗 }//插入函數 int HashTable::Insert(datatype f_word_key){int key = WordTransitionKey(f_word_key.word);//將單詞轉化為關鍵碼int i = H(key); //計算散列地址,設置比較的起始位置while (ht[i].key != 0){ //尋找空的散列單元i = (i + 1) % MaxSize; //向后探測一個位置} //whileht[i].key = key; //關鍵碼賦值ht[i].word = f_word_key.word; //單詞賦值ht[i].frequency = f_word_key.frequency; //詞頻賦值return i; //返回插入位置 }//獲取單詞以及頻率 datatype HashTable::Get(int a){return ht[a]; }//鏈地址法哈希表類 class HashTableLink{public:HashTableLink(); //構造函數,初始化開散列表~HashTableLink(); //析構函數,釋放同義詞子表結點int Insert(datatype fword); //插入Node* Search(string word); //查找void Print(); //輸出private:int H(int k); //散列函數Node* ht[MaxSize]; //開散列表 };//構造函數 HashTableLink::HashTableLink(){for (int i = 0; i < MaxSize; i++)ht[i] = NULL; //鏈式存儲結構指針置空 }//析構函數,釋放空間 HashTableLink :: ~HashTableLink(){Node* p = NULL, * q = NULL;for (int i = 0; i < MaxSize; i++){p = ht[i];q = p; //用來儲存pwhile (p != NULL){ //p非空p = p->next; //p后移delete q; //刪除qq = p;} //while} //for }//除留余數法-散列函數 int HashTableLink::H(int k){return k % MaxSize; }//輸出到屏幕和文本文件outfile6.txt void HashTableLink::Print() {system("cls"); //清屏ofstream fout; //文件寫操作 內存寫入存儲設備fout.open("outfile6.txt"); //打開文件fout << "單詞總數為:" << sum << endl;fout << "詞頻" << "\t" << "單詞" << endl;for (int i = 0; i < sum; i++) {fout << WF[i].frequency << "\t" << WF[i].word << endl;cout << WF[i].frequency << "\t" <<WF[i].word << endl;} //forsystem("pause"); //暫停 }//查找函數 Node* HashTableLink::Search(string word){int k = WordTransitionKey(word); //轉化為關鍵碼int j = H(k); //計算散列地址Node* p = ht[j]; //指針p初始化while (p != NULL){ //p非空if (p->data.word == word)return p; //已找到返回指針elsep = p->next; //p后移} //whilereturn nullptr; //未找到返回空指針 }//插入函數(前插法) int HashTableLink::Insert(datatype fword){int k = WordTransitionKey(fword.word); //轉化為關鍵碼fword.key = k; //給關鍵碼賦值int j = H(k); //計算散列地址Node* p = Search(fword.word); //調用查找函數if (p != nullptr) //p非空,表示該內容已經插入過了return -1; //已存在元素k,無法插入 else { //p為空,表示該內容未插入p = new Node; //生成新節點p->data.key = fword.key; //關鍵碼賦值p->data.frequency = fword.frequency; //詞頻賦值p->data.word = fword.word; //單詞賦值p->next = ht[j]; //新節點插入ht[j]ht[j] = p; //更新節點return 1; //插入成功標志 } }//哈希表菜單 void HashMenu(){while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---哈希表---" << endl;cout << "1.開放地址法哈希查找" << endl;cout << "2.鏈地址法哈希查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1 : OpenHashLocate(); //開放地址法哈希查找break;case 2 : LinkHashLocate(); //鏈地址法哈希查找break;case 3 : return; //退出函數default: cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause");} //switch} //whilereturn; }//開放地址法哈希查找菜單 void OpenHashLocateMenu(){HashTable HT;for (int i = 0; i < sum; i++)HT.Insert(WF[i]); //把數據插入到哈希表中double bulkfactor = sum / MaxSize; //裝填因子system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---開放地址單詞查找---" << endl;cout << "請輸入要查找的單詞:";string word;cin >> word;auto start = system_clock::now(); //開始時間int i = HT.Search(word); //獲取散列地址duration<double> diff = system_clock::now() - start; //現在時間 - 開始時間if (i) {cout << "此單詞為:" << HT.Get(i).word << endl;cout << "此單詞的詞頻:" << HT.Get(i).frequency << endl;cout << "查找該單詞所花費的時間:" << (diff.count())*1000 << "毫秒" << endl;cout << "平均查找長度:" << (1 + 1 / (1 - bulkfactor)) / 2 << endl;} //ifelsecout << "查找失敗" << endl;system("pause"); //暫停 }//開放地址法哈希查找 void OpenHashLocate(){HashTable HT;for (int i = 0; i < sum; i++)HT.Insert(WF[i]); //把數據插入到哈希表中while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---基于開放地址法的哈希查找---" << endl;cout << "1.詞頻統計" << endl;cout << "2.單詞查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1 : HT.Print(); //詞頻統計break;case 2 : OpenHashLocateMenu(); //開放地址法的哈希查找菜單break;case 3 :return;default: cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause"); //暫停} //switch} //while }//鏈地址法哈希查找 void LinkHashLocate(){HashTableLink HT;for (int i = 0; i < sum; i++)HT.Insert(WF[i]); //把數據插入到哈希表while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---基于鏈地址法的哈希查找---" << endl;cout << "1.詞頻統計" << endl;cout << "2.單詞查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1: HT.Print(); //詞頻統計break;case 2:LinkHashWordLocateMenu(); //單詞查找菜單break;case 3: return; //退出函數default: cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause"); //暫停} //switch} //while }//鏈地址法哈希查找菜單 void LinkHashWordLocateMenu(){HashTableLink HT;for (int i = 0; i < sum; i++)HT.Insert(WF[i]); //把數據插入到哈希表double load_factor = sum / MaxSize;//散列表的裝填因子system("cls");cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---鏈地址單詞查找---" << endl;cout << "請輸入要查找的單詞:";string word;cin >> word;auto start = system_clock::now(); //開始時間HT.Search(word);duration<double> diff = system_clock::now() - start; //現在時間 - 開始時間Node* p = HT.Search(word); //返回目標指針if (p != NULL) {cout << "此單詞為:" << p->data.word << endl;cout << "此單詞的詞頻:" << p->data.frequency << endl;cout << "查找該單詞所花費的時間:" << (diff.count())*1000 << "毫秒" << endl;cout << "平均查找長度:" << 1 + (load_factor) / 2 << endl;} //ifelsecout << "查找失敗" << endl;system("pause"); //暫停 }//二叉排序樹類 class BiSortTree{public:BiSortTree(datatype a[], int n); //帶參構造函數,對樹初始化~BiSortTree(){ //析構函數Release(root); } BiNode* InsertBST(datatype data){ //函數重載,插入數據域datareturn InsertBST(root, data);} BiNode* SearchBST(string word){ //函數重載,查找值為word的結點return SearchBST(root, word);} void printf(); //輸出函數private:void Release(BiNode* bt); //釋放空間BiNode* InsertBST(BiNode* bt, datatype data); //插入數據域dataBiNode* SearchBST(BiNode* bt, string word); //查找值為word的結點void InOrder(BiNode* bt); //中序遍歷函數調用BiNode* root; //二叉排序樹的根指針 };//構造函數 BiSortTree::BiSortTree(datatype a[], int n) {root = NULL; //根指針置空for (int i = 0; i < n; i++)root = InsertBST(root, a[i]); //遍歷,插入數據 }//輸出函數 void BiSortTree::InOrder(BiNode* bt){ //遞歸輸出二叉排序樹ofstream fout; //文件寫操作 內存寫入存儲設備fout.open("outfile4.txt", ios_base::out | ios_base::app); //打開文件并將內容追加到文件尾if (bt == NULL) //遞歸調用的結束條件,根指針為空return; //退出函數 else{InOrder(bt->lchild); //中序遞歸遍歷bt的左子樹cout << bt->data.frequency << "\t" << bt->data.word << endl; //訪問根結點bt的數據域,輸出到屏幕fout << bt->data.frequency << "\t" << bt->data.word << endl; //訪問根結點bt的數據域,輸出到文件fout.close(); //關閉文件InOrder(bt->rchild); //中序遞歸遍歷bt的右子樹 } //else }//輸出二叉排序樹到屏幕和outfile4.txt void BiSortTree::printf() {system("cls"); //清屏ofstream fout; //文件寫操作 內存寫入存儲設備fout.open("outfile4.txt");//打開文件fout << "單詞總數為:" << sum << endl;fout << "詞頻" << "\t" << "單詞" << endl;InOrder(root); //輸出函數system("pause"); //暫停return; //退出函數 }//遞歸查找函數,返回指針 BiNode* BiSortTree::SearchBST(BiNode* bt, string word){if (bt == NULL) return NULL; //未找到,返回NULLif (bt->data.word == word) return bt; //找到word,返回該指針else if (bt->data.word > word) //數據大于wordreturn SearchBST(bt->lchild, word); //遞歸查找左子樹else //數據小于wordreturn SearchBST(bt->rchild, word); //遞歸查找右子樹 }//遞歸插入函數 BiNode* BiSortTree::InsertBST(BiNode* bt, datatype data){if (bt == NULL){ //找到插入位置BiNode* s = new BiNode; //生成一個新的儲存空間s->data = data; //為數據域賦值s->lchild = NULL; //左孩子指針置空s->rchild = NULL; //右孩子指針置空bt = s; //根指針更新return bt; //返回根指針} //ifelse if (WordTransition(bt->data.word) > WordTransition(data.word)){ //根節點數據大于要插入的數據bt->lchild = InsertBST(bt->lchild, data); //更新左孩子指針return bt; //返回根指針} //else ifelse{ //根節點數據小于要插入的數據bt->rchild = InsertBST(bt->rchild, data); //更新有孩子指針return bt; //返回根指針} //else }//遞歸析構函數 void BiSortTree::Release(BiNode* bt){if (bt == NULL)return; //根指針為空直接退出else {Release(bt->lchild); //釋放左子樹Release(bt->rchild); //釋放右子樹delete bt; //釋放根結點} }// 二叉排序樹菜單 void BiTreeMenu(){while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---二叉排序樹查找---" << endl;cout << "1.二叉排序樹的順序查找" << endl;cout << "2.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1: BitreeLocateMenu(); //二叉排序樹查找菜單break; //退出switchcase 2: return; //退出函數default:cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause"); //暫停} //switch} //while }//二叉排序樹的順序查找菜單 void BitreeLocateMenu(){BiSortTree B(WF,sum);while(true){system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---基于二叉排序樹的順序查找---" << endl;cout << "1.詞頻統計" << endl;cout << "2.單詞查找" << endl;cout << "3.返回上一級" << endl;cout << "請按相應的數字鍵進行選擇:" << endl;int n;cin >> n;switch (n){case 1: B.printf(); break;case 2: BitreeWordLocMenu(); //二叉排序樹查找單詞菜單break;case 3:return; //退出函數default: cout << "輸入的不是有效符號,請重新輸入" << endl; system("pause"); //暫停} //switch} //while }//二叉排序樹查找單詞菜單 void BitreeWordLocMenu(){BiSortTree B(WF,sum);system("cls"); //清屏cout << "*******************基于不同策略的英文單詞的詞頻統計和檢索系統*******************" << endl;cout << "---二叉排序單詞查找---" << endl;cout << "請輸入要查找的單詞:";string word;cin >> word;auto start = system_clock::now(); //開始時間B.SearchBST(word);duration<double> diff = system_clock::now() - start; //現在時間 - 開始時間BiNode* p = NULL; //指針置空p = B.SearchBST(word);if (p != NULL) {cout << "此單詞為:" << p->data.word << endl;cout << "此單詞的詞頻:" << p->data.frequency << endl;cout << "查找該單詞所花費的時間:" << (diff.count())*1000 << "毫秒" << endl;cout << "平均查找長度:" << sum << endl;} //ifelsecout << "查找失敗" << endl;system("pause"); //暫停 }六、運行結果
這里通過查找同一個單詞來分辨不同查找方式的效率
七、總結
通過這次實驗,讓我對順序表、鏈表、二叉排序樹、連地址哈希表和開放地址哈希表的結構有了更深刻的認識;學會如何去使用基于以上結構的順序查找、折半查找等;還學會了如何輸出查找時間以及他們的ASL(平均查找長度)
總結
以上是生活随笔為你收集整理的数据结构 C++实现 基于不同策略的英文单词的词频统计和检索系统(糅合版)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DHT 爬虫的学习记录
- 下一篇: arduino+无源蜂鸣器制作音乐《诺言