数据结构设计--哈希表词频统计检索+职工电话号码查询系统

目录

一、哈希表词频统计

1.环境

2.语言

3.功能

4.源代码

二、职工电话号码查询系统

1.环境

2.语言

3.功能

4.源代码


一、哈希表词频统计

1.环境

vs code

2.语言

c++

3.功能

一篇英文文章(单词个数不超过1000个)存储在一个文本文件中,请设计程序,完成以下功能:

(1)从文件中读取英文单词(不区分大小写),过滤掉所有的标点,统计文章中各单词出现的次数。

(2)单词查找:

用哈希表作为查找表(自行设计哈希函数),分别实现基于线性探测法的单词查找和基于链地址法的单词查找,并分别计算其ASL。

(3)单词插入:

若查找失败,向哈希表中插入该单词。

4.源代码

#include<iostream>
#include<fstream>     
#include<cstring>    
#include<string>
#include<windows.h>
#include<conio.h>
#include<cmath>   
#include<time.h> 
#include<stdlib.h>
using namespace std;

//常量的定义 
const int MaxSize = 1000;    //文章单词最大容量
const char* file = "D:\\下载2\\English.txt";    //待检索文件
int sum;    //单词总数

// 词频顺序存储结构--线性探测法 
struct WordFrequency 
{    //词频
    string word;    //单词
    int frequency;    //频率
    int key;    //关键码
}WF[MaxSize];

typedef WordFrequency datatype;    //为数据类型定义一个新的名字

//词频链式存储结构--链地址法 
struct Node 
{
    datatype data;    //数据域
    Node* next;    //指针域
};

//读取文件函数声明
int StatisticalWord(string word);    //统计文章词频
void StatisticsData();    //数据统计
int  WordTransitionKey(string word);    //将单词转换为唯一关键码

//Hash函数声明
void HashMenu();    //哈希表菜单
void OpenHashLocateMenu();    //线性探测法哈希查找菜单
void OpenHashLocate();    //线性探测法哈希查找
void LinkHashLocate();    //链地址法哈希查找
void LinkHashWordLocateMenu();    //线性探测法哈希查找菜单

void MajorMenu();    //主菜单

//统计文章词频,把字符添加到结构体数组中 
int StatisticalWord(string word) 
{
    for (int i=0; i<MaxSize; i++) 
    {
        if (WF[i].word == word) 
        {    
            WF[i].frequency++;    //词频++
            return i;    //退出函数
        }    
    }
    //单词如果不重复,添加到哈希表中 
    WF[sum].word = word;    //添加单词
    WF[sum].frequency = 1;    //词频置为一
    WF[sum].key = WordTransitionKey(word);    //添加关键码
    sum++;    //单词总数++
    return 0;
}

//将单词转换为关键字--随机数法 
int  WordTransitionKey(string word) 
{
    int a[23] = {0,2,3,5,7,11,13,17,19,23,27,29,31,37,41,47,51,67,87,101,111,113,117};//用随机数法 
    int sumkey = 0;
    for (int i = 0; i < int(word.size()); i++) 
    {
        sumkey += int(word[i]);    //每个字符的ASCLL值相加
    }
    sumkey += int('a') * a[int(word.size())];//用a的ASCLL*一个随机的素数 
    return sumkey;
}

//读取文件,并进行词频统计
void StatisticsData() 
{
    system("cls");    //清屏
    ifstream fin;    //文件读操作,存储设备读取到内存中
    fin.open(file);    //关联文件file
    char 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;
            else
                word += ch;    //word不为空,拼接字母组成单词
        }    
        else 
        {
            if (word != "\0") 
            {    //判断之前的word里面是否有单词
                count++;    //有单词,总数++
                if (count>MaxSize) 
                {
                    cout << "文章单词超出统计上限,系统已退出" << endl;
                    fin.close();    //关闭文件
                    exit(0);    //退出程序
                    system("pause");    //暂停
                }
                StatisticalWord(word);    //存放到结构体数组里面--哈希数组 
            }    
            word = "\0";    //重置word,用于存放新单词
        }    
    }    
    fin.close();    //关闭文件
}

//线性探测法哈希表类
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表示该散列单元为空
    }
}

//哈希函数,除留余数法
int HashTable::H(int k) 
{
    return k % MaxSize;
}

//输出函数
void HashTable::Print() 
{
    system("cls");    //清屏
    cout << "单词总数为:" << sum << endl;
    for (int i = 0; i < sum; i++) 
    {
        cout << "单词:"<<WF[i].word << "\t" <<"词频:"<<WF[i].frequency << endl;
    }
    system("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;    //向后探测一个位置
    }    
    return 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;    //向后探测一个位置
    }
    ht[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;    //用来储存p
        while (p != NULL)
        {    //p非空
            p = p->next;    //p后移
            delete q;    //删除q
            q = p;
        }    //while
    }
}

//除留余数法-散列函数
int HashTableLink::H(int k)
{
    return k % MaxSize;
}

//输出到屏幕
void HashTableLink::Print() 
{
    system("cls");    //清屏
    cout << "单词总数为:" << sum << endl;
    for (int i = 0; i < sum; i++) 
    {
        cout << "单词:"<<WF[i].word << "\t" <<"词频:"<<WF[i].frequency<< endl;
    }
    system("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;    //已找到返回指针
        else
            p = p->next;    //p后移
    }    //while
    return NULL;    //未找到返回空指针
}

//插入函数(前插法)--链地址 
int HashTableLink::Insert(datatype fword)
{
    int k = WordTransitionKey(fword.word);    //转化为关键码
    fword.key = k;    //给关键码赋值
    int j = H(k);    //计算散列地址
    Node* p = Search(fword.word);    //调用查找函数
    if (p != NULL)    //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 << "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");
        }    
    }
    return;
}

//线性探测法哈希查找菜单
void OpenHashLocateMenu()
{
    HashTable HT;
    for (int i = 0; i < sum; i++)
        HT.Insert(WF[i]);    //把数据插入到哈希表中
    double a = (double)sum / MaxSize;    //装填因子
    system("cls");    //清屏
    cout << "*******************基于哈希表的英文单词词频统计和检索系统*******************" << endl;
    cout << "---线性探测单词查找---" << endl;
    cout << "请输入要查找的单词:";
    string word;
    cin >> word;
    int i = HT.Search(word);    //获取散列地址
    if (i) //查找成功的ASL 
    {
        cout << "此单词为:" << HT.Get(i).word << endl;
        cout << "此单词的词频:" << HT.Get(i).frequency << endl;
        double ans=(double)(1 + (1.00)/ (1 - a)) / 2; 
        printf("查找成功时ASL=%.2lf\n",ans);
    }
    else//查找失败,把单词加入到哈希表当中 ,并输出失败的ASL 
    {
        WF[sum].word=word;
        WF[sum].frequency=1;
        WF[sum].key=WordTransitionKey(word);
        HT.Insert(WF[sum]);
        sum++;
        cout << "查找失败" << endl;
        double ans=(double)(1+1/pow(1-a,2))/2;
        printf("查找失败时ASL=%.2lf\n",ans);
    }
    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");
        }    
    }
}

//链地址法哈希查找
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");
        }    
    }    
}

//链地址法哈希查找菜单
void LinkHashWordLocateMenu()
{
    HashTableLink HT;
    for (int i = 0; i < sum; i++)
        HT.Insert(WF[i]);    //把数据插入到哈希表
    double a= (double)sum / MaxSize;//散列表的装填因子
    system("cls");
    cout << "*******************基于哈希表的英文单词词频统计和检索系统*******************" << endl;
    cout << "---链地址单词查找---" << endl;
    cout << "请输入要查找的单词:";
    string word;
    cin >> word;
    HT.Search(word);
    Node* p = HT.Search(word);    //返回目标指针
    if (p != NULL) 
    {
        cout << "此单词为:" << p->data.word << endl;
        cout << "此单词的词频:" << p->data.frequency<< endl;
        double ans=1+(double)(a)/2;
        printf("查找成功时ASL=%.2lf\n", ans);
    }    //if
    else
    {
        WF[sum].word=word;
        WF[sum].frequency=1;
        WF[sum].key=WordTransitionKey(word);
        HT.Insert(WF[sum]);
        sum++;
        cout << "查找失败" << endl;
        double e=2.718281;
        double ans=(double)(a+pow(e,-a)); 
        printf("查找失败时ASL=%.2lf\n",ans);
    }
    system("pause");    //暂停
}
//主菜单
void MajorMenu() 
{
    while (true) 
    {
        cout << "*******************基于哈希表的英文单词词频统计和检索系统*******************" << endl;
        cout << "---菜单---" << endl;
        cout << "1.基于哈希表的查找" << endl;
        cout << "2.退出系统" << endl;
        cout << "请按相应的数字键进行选择:" << endl;
        int n;
        cin >> n;
        switch (n) 
        {
            case 1:
                HashMenu();
                break;
            case 2:
                cout << "系统已退出" << endl;
                return;
            default:
                cout << "输入的不是有效符号,请重新输入" << endl;
                system("cls");    //清屏
                system("pause");    //暂停
        }    
    }    
}
//主函数
int main() 
{
    ifstream fin;
    fin.open(file);//获取文件English.txt 
    if (!fin.is_open()) 
    {
        cout << "EngLish.txt文件不存在,请检查文件名或者目录下文件是否存在..." << endl;
        system("pause");
        return 0;
    }    
    else 
    {
        cout << "EngLish.txt文件加载中..." << endl;
        Sleep(1000);//延时函数,延时1秒
    }    
    StatisticsData();    //数据统计
    MajorMenu();//主菜单
    return 0;
}

二、职工电话号码查询系统

1.环境

vs code

2.语言

c++

3.功能

设计散列表,实现职工电话号码查询系统,要求:

(1) 每个记录包括下列内容:

(电话号码(11位) 、工号(5位) 、姓名、性别、院系名)总记录数不少于300条。

(2)从文件中读入各记录,分别以电话号码和用户名为关键字建立散列表(散列函数要求使用除留余数法,采用开放定址法处理冲突)

(3)查找并显示给定电话号码的记录,并输出查找长度。

(4)查找并显示给定用户名的记录(若有同名记录,则输出全部同名用户信息),并输出查找长度。

(5) 从文件读入各记录,以工号为关键字建立散列表(散列函数要求使用除留余数法,采用链地址法处理冲突)。

(6) 查找并显示给定院系的所有职工信息。

4.源代码

#include<bits/stdc++.h>
#include<algorithm>
using namespace std;
const int MAXSIZE=300;
int n;//读入数据数 
typedef struct
{
    string tel;//电话
    string num;//工号
    string name;//姓名
    string sex;//性别
    string col;//院系 
}Hash;

typedef Hash Elemtype;//重新定义一个类型 

typedef struct LNode
{
    Elemtype data;
    LNode *next;
}*LinkList;

Hash ht[MAXSIZE];//定义结构体线性表 

//初始化单链表 
void InitList(LinkList h[MAXSIZE])
{
    for(int i=0;i<MAXSIZE;i++)
    {
        h[i]=new LNode;
        h[i]->next=NULL;
    }
}

//初始化线性表
void init()
{
    n=0;
    return ;
} 

//将文件中的数据逐条读入顺序表L中
void ReadData(Hash ht[])
{
    int i=0;
    init();     //初始化顺序表
    ifstream infile("D:\\下载2\\edg.txt");  //以输入的方式(读文件的方式)打开文件d:\book.txt
    while(!infile.eof())   //只要文件没读完,就读一行数据到顺序表L中的第i个分量中
    {
        infile>>ht[i].tel;    
        infile>>ht[i].num;  
        infile>>ht[i].name;
        infile>>ht[i].sex;
        infile>>ht[i].col;
        i++;
    }
    n=i;      //修改顺序表的长度
    infile.close ();  //关闭文件
} 

int H(int x)//除留余数法 
{
    return x%MAXSIZE;
}

int KEY(string x)//求关键字 
{
    int a[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,51};//减少冲突 
    int ans=0;
    for(int i=0;i<x.size();i++)
         ans+=int(x[i]);
    return (a[x.size()]*ans+MAXSIZE)%MAXSIZE;
}

void name_create(int op)//开放寻址法电话号码/姓名建表
{
    Hash a[MAXSIZE];
    int ans=0;
    for(int i=0;i<n;i++)
    {
        int key;
        if(op==1)
            key=H(KEY(ht[i].tel));
        else if(op==2)
            key=H(abs(KEY(ht[i].name)));
        int f=key;
        while(a[key].name!="")//如果当前有冲突,向下一个继续探测 
        {
            key++;
            if(key==MAXSIZE-1) key=0;
            if(f==key) break;//再次探测这个位置,跳出循环 
        }
        a[key]=ht[i]; //插入哈希表中,也就是将结构体数组赋值 
    }    
    cout<<"输出开放寻址法所建的哈希表:"<<endl;
    for(int i=0;i<MAXSIZE;i++)
    {
        if(a[i].name!="")
        {
            cout<<a[i].tel<<" "<<a[i].num<<" "<<a[i].name<<" "<<a[i].sex<<" "<<a[i].col<<endl;
        }
    }
    cout<<endl;
    return ;
} 

void tel_search()//按电话号码查找 
{
    cout<<"请输入一个电话号码:";
    string x;
    cin>>x;
    cout<<endl;
    int ans=0;
    int p=0; 
    for(int i=0;i<n;i++)
    {
        if(ht[i].tel==x)
        {
            p++;//设置访问标志 
            cout<<ht[i].tel<<" "<<ht[i].num<<" "<<ht[i].name<<" "<<ht[i].sex<<" "<<ht[i].col<<endl;
        }
        ans++;//继续查找,长度+1
        if(p) break; //如果查到,退出循环 
    }
    if(p)
        cout<<"查找长度为:"<<ans<<endl;
    else cout<<"未查找到该用户!"<<endl;
    return ;
} 

void name_search()
{
    cout<<"请输入一个姓名:";
    string x;
    cin>>x;
    cout<<endl;
    int ans=0;
    int p=0;
    int q=0;
    for(int i=n-1;i>=0;i--)
    {
        if(ht[i].name==x)
        {
            q=i;
            break;
        }
    } 
    for(int i=0;i<n;i++)
    {
        if(ht[i].name==x)
        {
            p++;//设置访问标志 
            cout<<ht[i].tel<<" "<<ht[i].num<<" "<<ht[i].name<<" "<<ht[i].sex<<" "<<ht[i].col<<endl;
        }
    }
    if(p)
        cout<<"查找长度为:"<<q+1<<endl;
    else cout<<"未查找到该用户!"<<endl;
    return ;
}

void num_create()//基于链地址法工号创建哈希表 
{
    LinkList h[MAXSIZE];
    InitList(h);
    int ans=0;
    for(int i=0;i<n;i++)
    {
        int key=H(KEY(ht[i].num));
        LinkList p=new LNode;
        p=h[abs(key)];
        while(p->next!=NULL) p=p->next;//让p指向尾节点 ,用尾插法 建表 
        LinkList q=new LNode;
        q->data.name=ht[i].name;//复制姓名 
        q->data.col=ht[i].col;//复制学院 
        q->data.num=ht[i].num;//复制工号 
        q->data.sex=ht[i].sex;//复制性别 
        q->data.tel=ht[i].tel;//复制电话 
        p->next=q;//尾插发 
        q->next=NULL;//将表尾置空 
    }
    cout<<"输出链地址法建表职工信息:"<<endl;
    for(int i=0;i<MAXSIZE;i++)
    {
        LinkList p=new LNode;
        if(h[i]->next==NULL) continue;
        else 
        {
            p=h[i]->next;
            while(p)
            {
                cout<<p->data.col<<" "<<p->data.name<<" "<<p->data.num<<" "<<p->data.sex<<" "<<p->data.tel<<endl;
                p=p->next;
            }
        }
    }
    return ;
}

void query()//输出给定院系职工信息
{
    cout<<"请输入一个院系:";
    string op;
    cin>>op;
    cout<<"该院系所有的职工为:"<<endl;
    for(int i=0;i<n;i++)
    {
        if(ht[i].col==op)
        {
            cout<<ht[i].tel<<" "<<ht[i].num<<" "<<ht[i].name<<" "<<ht[i].sex<<" "<<ht[i].col<<endl;
        }
    }
    return ;
} 

void menu()
{
    cout<<"***********欢迎使用职工电话号码查询系统*************"<<endl;
    cout<<"***********1.开放寻址法以电话建立哈希表*************"<<endl;
    cout<<"***********2.开放寻址法以姓名建立哈希表*************"<<endl;
    cout<<"***********3.查询电话号码记录并输出长度*************"<<endl;
    cout<<"***********4.查找用户名并且输出查找长度*************"<<endl;
    cout<<"***********5.链地址法以工号来建立哈希表*************"<<endl;
    cout<<"***********6.查找显示给定院系的职工信息*************"<<endl;
}

int main()
{
    ReadData(ht);//读取信息 
    while(1)
    {
        menu();
        int op;
        cout<<"请输入一个序号:"; 
        cin>>op;
        puts("");//换行 
        switch(op)
        {
            case 1:name_create(op); 
                break;
            case 2:name_create(op);
                break;
            case 3:tel_search();
                break;
            case 4:name_search();
                break;
            case 5:num_create();
                break;
            case 6:query();
                break;
            default:printf("序号错误!");
                break;
        }
    }
    return 0;
}

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值