天天看點

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

提示:文章寫完後,目錄可以自動生成,如何生成可參考右邊的幫助文檔

文章目錄

  • 前言
  • 一、問題描述
  • 二、問題描述
    • (1)選用的散列函數
    • (2)散列因子
    • (3)解決沖突的方法
  • 三、實驗結果及分析
    • (1)實驗資料描述
    • (2)實驗結果
    • (3)性能分析
  • 四、實驗總結
  • 五、源代碼
    • (1)随機生成電話号碼系統代碼
    • (2)電話号碼查詢系統代碼

前言

記錄下上學期的資料結構實驗

本電話号碼查詢系統基于兩種散列方法和兩種解決沖突的方法實作

提示:以下是本篇文章正文内容,下面案例可供參考

一、問題描述

設計散清單,實作電話号碼查找系統。設電話号碼簿長度為n(0≤n≤10000),系統應該實作如下工作:

⑴ 電話号碼簿儲存在磁盤檔案中,每一條電話号碼記錄包含資料項:編号(唯一),使用者名,通信位址,電話号碼(手機号)

⑵ 建立散清單:系統運作時,讀取磁盤檔案的電話号碼,建構散清單,用于查詢。要求:自選散列函數(至少2種),自選解決沖突的方法(至少2種),分别以電話号碼和使用者名為關鍵字,建立散清單。

⑶ 查詢:根據輸入的使用者名,查找并顯示給定使用者的資訊。

⑷ 性能分析:

① 計算并輸出不同散列函數、不同解決沖突方法的平均查找長度。

② 通過改變散列因子、改變哈希函數等方式,改善平均查找長度:通過資料表、柱形圖、折線圖等方式,記錄實驗資料的變化情況,對影響平均查找長度變化的原因進行分析。

二、問題描述

(1)選用的散列函數

①除留餘數法

分析:

ⅰ.以電話号碼為關鍵字時,将字元串類型的電話号碼轉換成long型資料,除以表長,剩下的餘數作為其在散清單中的位址,即pos值。

ⅱ.以姓名為關鍵字時,将字元串類型的姓名的每一位上的字母轉換成ascii碼,此時還是内容為數字的字元串,再将字元串轉換成long型資料,除以表長,剩下的餘數作為其在散清單中的位址,即pos值。

②折疊法

分析:

ⅰ.以電話号碼為關鍵字時,将字元串類型的電話号碼,切割成四組資料,每組資料的個數為3 3 3 2,轉化成int型資料,取第一組資料和第三組資料、第二組和第四組的逆置數相加,得到的資料取後四位數,作為其在散清單中的位址,即pos值。

ⅱ.以姓名為關鍵字時,将字元串類型的姓名的每一位上的字母轉換成ascii碼,此時還是内容為數字的字元串,再切割成四組資料,每組資料的個數為3 3 3 2,轉化成int型資料,取第一組資料和第三組資料、第二組和第四組的逆置數相加,得到的資料取後四位數,作為其在散清單中的位址,即pos值。

(2)散列因子

散清單的散列因子定義為:α= 填入表中的元素個數/散清單的長度。α是散清單裝滿程度的标志因子。由于表長是定值,α與元素個數成正比,是以,α越大,填入表中的元素較多,産生沖突的可能性就越大;α越小,填入表中的元素較少,産生沖突的可能性就越小。

為了探究不同散列因子對平均查找長度ASL的影響,在利用線性探測法解決沖突時,本實驗中

拟取用 α 的值為 0.85、0.75、0.65、0.55;利用拉鍊法解決沖突時,本實驗中 α 拟選用 1、1.2、

1.4、1.6。

(3)解決沖突的方法

①線性探測法

該方法的基本思想是,當關鍵字key的哈希位址p出現沖突時,順序檢視表中下一單元,以p為基礎産生另一個哈希位址p1,如果p1仍然沖突,再以p為基礎産生p2,……,直到找到一個不沖突的哈希位址pi,将相應元素存入其中。沖突發生時,順序檢視表中下一單元,,直到找出一個空單元或者查遍全表。

缺點:容易造成元素聚集,降低查找效率

②拉鍊法

該方法基本思想是将所有的哈希位址為i的元素構成一個同義詞鍊的單連結清單,并将單連結清單的頭指針存在哈希表的第i個單元中。

優點:避免了動态調整的開銷

三、實驗結果及分析

(1)實驗資料描述

1.資料集規模

本實驗拟采用 10000 組聯系人記錄。每一行記錄一位聯系人的編号、姓名、位址、電話号碼。

檔案存儲于FinalDataSet_10000.txt。檔案存儲格式如圖 1 所示:

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖1 實驗資料集内容

2.資料集來源

本次實驗的資料全部随機生成。

資料内容:

編号:1-10000,按順序輸出即可;

姓名:三個英文字母,字元串。随機生成0-25的int型資料,再通過循環從char型字母表數組中利用下标讀出并存儲到data數組的姓名域中去;

位址:長度不等,字元串。這裡使用的城市資料僅為20組,每組城市資料存儲在Country結構體中,結構體中有city[],用于存放每組城市名稱,所有的城市資料存儲在Country類型的數組中。随機生成0-20的int型資料,再通過循環從Country類型的數組中利用下标讀出并存儲到data數組的位址域中去。

電話号碼:11位0-9的資料,字元串。根據一般電話号碼的規律,首位都是1,是以其他10位是随機生成的。随機生成0-9的int型資料,再通過循環從char型數字表數組中利用下标讀出并存儲到data數組的電話号碼域中去;

3.磁盤檔案存儲格式:.txt格式。

(2)實驗結果

1.以電話号碼為關鍵字

①哈希函數為除留餘數法,解決沖突的方法為線性探測法,查找成功,實驗結果如圖2、3所示。

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖2 以電話号碼為關鍵字查找成功的實驗結果

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖3 對應在磁盤檔案中的資料

②哈希函數為除留餘數法,解決沖突的方法為拉鍊法,查找失敗,實驗結果如圖4所示。

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖4 以電話号碼為關鍵字查找失敗的實驗結果

2.以姓名為關鍵字

①哈希函數為除留餘數法,解決沖突的方法為線性探測法,查找成功,實驗結果如圖5、6所示。

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖5 以姓名為關鍵字查找成功的實驗結果

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖6對應在磁盤檔案中的資料

②哈希函數為除留餘數法,解決沖突的方法為拉鍊法,查找失敗,實驗結果如圖7所示。

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖7 以電話号碼為關鍵字查找失敗的實驗結果

(3)性能分析

①分析填充因子和沖突方法與 ASL 的關系

表1 在不同的散列因子和解決沖突方法下,查找成功和查找失敗的ASL

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼
資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖8 在不同的散列因子和解決沖突的方法下,查找成功的ASL折線圖

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖9 在不同的散列因子和解決沖突的方法下,查找失敗的ASL折線圖

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖10 線上性檢測法下,不同的散列因子,查找成功和查找失敗的ASL折線圖

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖11 在拉鍊法下,不同的散列因子,查找成功和查找失敗的ASL折線圖

由表1和圖8-11可見,在采用相同的解決沖突的方法時,ASL随散列因子增大而變大。當解決沖突方法為線性探測法時,查找失敗比查找成功的ASL大,且增幅也随散列因子增大而變大。但當解決沖突方法為拉鍊法時,查找成功比查找失敗的ASL大,且增幅并不随散列因子增大而改變。

②分析資料規模與 ASL 的關系

資料結構實驗:電話号碼查詢系統前言一、問題描述二、問題描述三、實驗結果及分析四、實驗總結五、源代碼

圖12 在散列因子為0.75時,不同的資料規模與ASL之間的折線圖

在散列因子α為0.75的情況下,進行了實驗,實驗資料如圖12所示。顯然由圖可知,在相同的散列因子的情況下,随着資料規模的增大,ASL并沒有明顯的變化,資料基本都浮動在2.5上下。我認為資料規模與ASL之間沒有直接的關系。

四、實驗總結

在測試了不同的解決沖突辦法、不同的散列因子和不同的資料規模對ASL的影響後,我得到了以下的結論:

a.當散列因子小于1時,解決沖突的方法可以選擇線性探測法。ASL随着散列因子α的增大而增大,且增幅随之變大。是以,當解決沖突方法為線性探測法時,要慎重選擇散列因子α。散列因子α過大,平均查找長度ASL過大,查找效果差;散列因子α過小,平均查找長度ASL雖然會較小,但是需要的存儲空間随之變大了,是以在設計解決沖突方法為線性探測法的散清單時,要選擇合适的散列因子α。

b.當散列因子大于1時,解決沖突的方法可以選擇拉鍊法法。ASL随着散列因子α的增大而增大,但增幅并不随散列因子α的增大而改變,而是幾乎不變。是以,适當選擇拉鍊法的散列因子,可以表現出良好的查找性能。

c.由圖表分析可得,解決沖突方式為拉鍊法受散列因子α的影響較小,解決沖突方式為線性探測法受散列因子α的影響較大。是以,拉鍊法更為穩定,性能更好。

d.資料規模較小時,解決沖突方式采用線性探測法、拉鍊法,性能差别都不是很大,均能表現出良好的查找性能,但是當資料規模變大的時候,采用線性探測法解決沖突的方法會使沖突增多,此時采用拉鍊法可以表現出更好的查找性能。

e.在實際操作的過程中,特别是在處理以姓名為關鍵字的時候,我發現有很多人的名字是重複的,這種情況在現實生活中也會存在,這也是沖突的其中一種方式,是以針對這種情況,我分不同的解決沖突方法進行讨論。

①線性探測法。當發現關鍵字重複時,再次通過線性探測,在與之重複的關鍵字周圍尋找一個空表,将其填入,即可解決沖突,但要注意,要使用一個标志flag來記錄某關鍵字重複的次數,借助該标志flag在查詢關鍵字時友善找到所有重複的元素。

②拉鍊法。當發現關鍵字重複時,直接将該節點插入散清單的與重複關鍵字相同的位置後的頭結點,即可解決沖突,但這個方法也需要使用一個标志flag來記錄某關鍵字重複的次數,用來友善找到所有重複的元素。

五、源代碼

(1)随機生成電話号碼系統代碼

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

#define N 10000 //元素最大個數
typedef struct {
    int no;  //編号
    char name[3];//名字
    char address[10];//位址
    char tel[12];//電話号碼
} NODE;
typedef struct {
    char data[10];
} Country;
Country country[10];

void creatfile(NODE data[], int *n);//建立磁盤檔案f:\resource.dat
int isTelRepeated(char tel[]);

void initCountry();

int main() {
    NODE DATA[N];
    int n;
    creatfile(DATA, &n);
    return 0;
}

void creatfile(NODE data[], int *n) {
    FILE *fp;
    int i, key, flag;
    int temp_n;
    char temp_tel[11];
    unsigned seed;
    *n = N;
    char num[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
    char alphabet[26] = {'a', 'b', 'c', 'd', 'e', 'f', 'g',
                         'h', 'i', 'j', 'k', 'l', 'm', 'n',
                         'o', 'p', 'q', 'r', 's', 't',
                         'u', 'v', 'w', 'x', 'y', 'z'};//字母表
    /*char ALPHABET[26] = {'A', 'B', 'C', 'D', 'E', 'F', 'G',
                         'H', 'I', 'J', 'K', 'L', 'M', 'N',
                         'O', 'P', 'Q', 'R', 'S', 'T',
                         'U', 'V', 'W', 'X', 'Y', 'Z'};//字母表*/
    initCountry();
    if ((fp = fopen("/Users/xiaoyee/Desktop/資料結構實驗作業/實驗報告/電話号碼查詢系統/1/TelDataSet_10000.txt", "w")) == NULL) {
        printf("can't open the file!\n");
        exit(0);
    }
    seed = time(NULL);
    srand(seed);  //設定随機種子
    for (i = 0; i < *n;i++) {
        for (int k = 0; k < 3; k++) {
            key = rand() % 26;
            data[i].name[k] = alphabet[key];
        }
        data[i].name[3] = '\0';
    }

    for (i = 0; i < *n;i++) {
        key = rand() % 20;
        for (int k = 0; k < 10; k++) {
            data[i].address[k] = country[key].data[k];
        }
    }

    for (i = 0; i < *n;) {
        temp_tel[0] = '1';
        for (int k = 1; k < 11; k++) {
            key = rand() % 10;
            temp_tel[k] = num[key];
        }
        temp_tel[11] = '\0';
        //寫一個整數到磁盤檔案
        flag = 1;
        if (isTelRepeated(temp_tel)) {
            flag = 0;
            break;
        }
        if (flag) {
            for (int k = 0; k < 11; k++) {
                data[i].tel[k] = temp_tel[k];
            }
            i++;
        }
    }

    for (i = 0; i < *n; i++) {
        fprintf(fp, "%d ", i + 1);  //寫一個整數到磁盤檔案
        fprintf(fp, "%s ", data[i].name);  //寫一個整數到磁盤檔案
        fprintf(fp, "%s ", data[i].address);  //寫一個整數到磁盤檔案
        fprintf(fp, "%s\n", data[i].tel);  //寫一個整數到磁盤檔案
    }
    fclose(fp);
}

void initCountry() {
    FILE *fp;
    char temp[10];
    if ((fp = fopen("/Users/xiaoyee/Desktop/資料結構實驗作業/實驗報告/電話号碼查詢系統/1/Country_data.txt", "r")) == NULL) {
        printf("can't open the file!\n");
        exit(0);
    }
    for (int i = 0; i < 20; i++) {
        fscanf(fp, "%s", temp);
        for (int j = 0; j < 10; j++) {
            country[i].data[j] = temp[j];
        }

    }
}

int isTelRepeated(char tel[]) {
    FILE *fp;
    char temp_tel[11];
    if ((fp = fopen("/Users/xiaoyee/Desktop/資料結構實驗作業/實驗報告/電話号碼查詢系統/1/TelDataSet_10000.txt", "r")) == NULL) {
        printf("can't open the file!\n");
        exit(0);
    }
    for (int i = 1; i <= N; i++) {
        fscanf(fp, "%s", temp_tel);
        if (strcmp(tel, temp_tel) == 0) {
            return 1;
        }
    }
    return 0;
}
           

(2)電話号碼查詢系統代碼

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define NIL -1   //定義初始值
#define M 13333    //表長
#define N 10000     //關鍵字個數
// α=0.75

typedef long keytype;
//散清單結點類型
typedef struct {
    int no;  //編号
    char *name;//名字
    char *address;//位址
    char *tel;//電話号碼
} NODE;

typedef struct pos {
    keytype pos;
    int flag;
    struct pos *next;
} POS;

//初始化哈希表,将姓名和電話号碼初始化!
void init(POS *table);

int increment(int i);//某種探測方法

int HASH_1(keytype key, int i);//将某鍵值轉換成位置
//在散清單中搜尋指定的鍵值
int search_tel(POS *table, char *tel, int *pos);

//在散清單中搜尋指定的鍵值
int search_name(POS *table, char *name, int *pos);

//pos傳回鍵值的位置
//将一個關鍵字添加到哈希表中(以電話号碼為關鍵字)
void insert_tel(POS *table_tel, int no, char *name);

//将一個關鍵字添加到哈希表中(以姓名為關鍵字)
void insert_name(POS *table_name, int no, char *tel);

//void insert_pos(POS *table_name, int i, int pos);

//建立哈希表(以電話号碼為關鍵字)
void creat(NODE *htable);

//将姓名轉化為數字
long converse_name(char *name);

//輸出想要搜尋的關鍵字的相關資訊
void prn(NODE *htable, int no);

//輸出哈希表
void prnnn(NODE *htable, POS *table_name, int pos);

//成功查找的ASL
float success_ASL();

//失敗查找的ASL
float fail_ASL();
//*******************************************************
//除留餘數法作為散列函數,線性探測法解決沖突
//*******************************************************

void menu();

//********************************************************
//主函數
//********************************************************
NODE htable[N];//定義結點表
POS table_tel[M];//定義哈希表(以電話号碼為關鍵字)
POS table_name[M];//定義哈希表(以姓名為關鍵字)
int main() {

    int op;//菜單選擇
    int i;
    int pos;
    char *tel;
    char *name;
    init(table_tel);    //哈希表初始化
    init(table_name);    //哈希表初始化
    creat(htable);
    menu();
    scanf("%d", &op);
    printf("----------------------------------------------\n");
    while (op != 3) {
        switch (op) {
            case 1: {
                tel = (char *) malloc(sizeof(char));
                printf("請輸入你想要查詢的電話号碼:");
                scanf("%s", tel);
                i = search_tel(table_tel, tel, &pos);
                if (i) {  //搜尋指定鍵值
                    printf("找到該電話号碼!!!\n");
                    printf("成功查找的平均查找長度ASL:%f\n", success_ASL());
                    prn(htable, table_tel[pos].pos);//table_tel[pos].pos=no
                } else {
                    printf("未找到該電話号碼!!!\n");
                    printf("失敗查找的平均查找長度ASL:%f\n", fail_ASL());
                }
            }
                break;
            case 2: {//?
                name = (char *) malloc(sizeof(char));
                printf("請輸入你想要查詢的姓名:");
                scanf("%s", name);
                i = search_name(table_name, name, &pos);//在散清單中查找被插入的鍵值
                if (i) {  //搜尋指定鍵值
                    printf("找到該姓名!!!\n");
                    printf("成功查找的平均查找長度ASL:%f\n", success_ASL());
                    if (table_name[pos].flag != 1)
                        prnnn(htable, table_name, pos);
                    else
                        prn(htable, table_name[pos].pos);//table_name[pos].pos=no
                } else {
                    printf("未找到該姓名!!!\n");
                    printf("失敗查找的平均查找長度ASL:%f\n", fail_ASL());
                }
            }
                break;
            case 3:
                exit(0);
            default: {
                printf("您輸入的操作不合法,請重新輸入!\n");
                fflush(stdin);//防止不斷從緩沖區取數,造成循環
                break;
            }
        }
        printf("\n");
        menu();
        scanf("%d", &op);
    }
    return 0;
}


//********************************************************
//初始化哈希表
//********************************************************
void init(POS *table) {
    POS *p = table;
    for (; p < table + M; p++) {
        p->pos = NIL;//初始化表元素的鍵值
        p->flag = 0;
        p->next = NULL;
    }
}
//********************************************************
//開放定址的哈希函數:折疊法
//構造哈希函數
//********************************************************

//********************************************************
//開放定址的哈希函數:除留餘數法
//構造哈希函數
//********************************************************
int increment(int i)  //某種探測方法
{
    return i;  //增量為i
}

int HASH_1(keytype key, int i)  //将某鍵值轉換成位置
{
    return ((int) (key % M) + increment(i)) % M;   //線性探測
}

//********************************************************
//在散清單中搜尋指定的鍵值
//pos傳回鍵值的位置
//********************************************************
int search_tel(POS *table_tel, char *tel, int *pos) {
    int i = 0;
    long s;
    do {
        s = atol(tel);//字元串電話号碼轉換為long型資料
        *pos = HASH_1(s, i);//開放定址的散列函數
        if (table_tel[*pos].pos == NIL)
            return 0;   //表未滿,沒找到
        if (strcmp(htable[table_tel[*pos].pos].tel, tel) == 0) return *pos; //找到
    } while (++i < M);
    return -1; //表滿,沒找到
}

//将姓名轉化為數字
long converse_name(char *name) {
    long temp = 0;
    int i = 10000;
    while (*name != '\0') {
        temp += ((*name - 'a') * i);
        i /= 100;
        name++;
    }
    return temp;
}

int search_name(POS *table_name, char *name, int *pos) {
    int i = 0;
    long k;
    k = converse_name(name);
    do {
        *pos = HASH_1(k, i);//開放定址的散列函數
        if (table_name[*pos].pos == NIL)
            return 0;   //表未滿,沒找到
        if (strcmp(htable[table_name[*pos].pos].name, name) == 0) return *pos; //找到
    } while (++i < M);
    return -1; //表滿,沒找到
}

//********************************************************
//将一個關鍵字添加到哈希表中
//********************************************************
void insert_tel(POS *table_tel, int no, char *tel) {//将一個關鍵字添加到哈希表中
    int i;
    int pos;
    i = search_tel(table_tel, tel, &pos);  //在散清單中查找被插入的鍵值
    if (i == 0) {  //表不滿,該結點不存在
        table_tel[pos].pos = no;
    } else if (i == -1)
        printf("表滿,無法插入!\n");
    else printf("關鍵字重複,無法插入!\n");
}

void insert_name(POS *table_name, int no, char *name) {
    int i, pos;
    int t = 1;
    long k;
    i = search_name(table_name, name, &pos);  //在散清單中查找被插入的鍵值
    if (i == 0) {  //表不滿,該結點不存在
        table_name[pos].pos = no;
        table_name[pos].flag = 1;
    } else if (i == -1)
        printf("表滿,無法插入!\n");
    else {
        k = converse_name(name);
        table_name[i].flag++;//重複的次數+1
        do {
            pos = HASH_1(k, t);//開放定址的散列函數
            if (table_name[pos].flag == 0) {
                table_name[pos].pos = no;
                table_name[pos].flag = 1;
                //insert_pos(table_name, i, pos);
                break;
            }
        } while (++t < M);
        // printf("關鍵字重複,無法插入!\n");
    }
}
/*
void insert_pos(POS *table_name, int i, int position) {
    Pos p;
    p = table_name[i].next;
    while (p != NULL)
        p = p->next;
    p->next = &table_name[position];
    printf(p->next->flag);
}*/

//********************************************************
//從磁盤檔案中讀入資料,并存入結點表中
//********************************************************
void creat(NODE *htable) {
    FILE *fp;
    int no;
    char *name;
    char *address;
    char *tel;
    if (M < N) {
        printf("散列因子>1,結點個數超過表長,無法建立!\n");
        return;
    }
    if ((fp = fopen("/Users/xiaoyee/Desktop/資料結構實驗作業/實驗報告/電話号碼查詢系統/1/FinalDataSet_10000.txt", "r")) == NULL) {
        printf("can't open the file!!");
        exit(0);
    }
    while (!(feof(fp))) {
        name = (char *) malloc(sizeof(char));
        address = (char *) malloc(sizeof(char));
        tel = (char *) malloc(sizeof(char));//非常重要!!!
        fscanf(fp, "%d", &no);
        fscanf(fp, "%s", name);
        fscanf(fp, "%s", address);
        fscanf(fp, "%s", tel);
        htable[no].no = no;
        htable[no].name = name;
        htable[no].address = address;
        htable[no].tel = tel;  //找到開放位置,将鍵值加入
        insert_tel(table_tel, no, tel);
        insert_name(table_name, no, name);
    }
    fclose(fp);
}


//********************************************************
//輸出哈希表
//********************************************************
void prn(NODE *htable, int no) {
    printf("編号:%d\t", htable[no].no);
    printf("姓名:%s\t", htable[no].name);
    printf("城市:%s\t", htable[no].address);
    printf("城市:%s\n", htable[no].tel);
    printf("\n");
}

//輸出哈希表
void prnnn(NODE *htable, POS *table_name, int pos) {
    int no = 0;
    int i = pos;
    POS *p;
    p = (POS *) malloc(sizeof(POS));
    //令p為table_name[i],即重複元素值相同的第一個元素
    p->pos = table_name[pos].pos;
    p->flag = table_name[pos].flag;
    p->next = table_name[pos].next;
    printf("查詢到該姓名在該電話号碼查詢系統中重複!\n");
    printf("現将所有是該姓名的人查詢如下:\n");
    for (int k = 0; k < table_name[pos].flag;) {
        if (strcmp(htable[table_name[pos].pos].name, htable[table_name[i].pos].name) == 0) {
            no = table_name[i].pos;
            printf("編号:%d\t", htable[no].no);
            printf("姓名:%s\t", htable[no].name);
            printf("城市:%s\t", htable[no].address);
            printf("城市:%s\n", htable[no].tel);
            k++;
        }
        i++;
    }
}

//成功查找的ASL
float success_ASL() {
    float i = 1 - (1.0 * N) / M;
    return (1 + 1 / i) / 2;
}

//失敗查找的ASL
float fail_ASL() {
    float a = (1.0 * N) / M;
    float i = 1 - a;
    return (1 + 1 / (i * i)) / 2;
}

/*void prnnn(NODE *htable) {
    NODE *p = htable;
    for (; p < htable + M; p++)
        if (p->tel != NIL) {
            printf("編号:%d\t", p->no);
            printf("姓名:%s\t", p->name);
            printf("城市:%s\t", p->address);
            printf("電話号碼:%ld\t", p->tel);//如果某位址不開放,則輸出相應的鍵值
        }

    printf("\n");
}*/

void menu() {
    printf("----------------------------------------------\n");
    printf("*************歡迎使用電話号碼查詢系統*************\n");
    printf("----------------------------------------------\n");
    printf("請選擇你想要進行的查詢:");
    printf(" 1.以電話号碼為關鍵字進行查詢\n");
    printf("\t\t\t\t    2.以姓名為關鍵字進行查詢\n");
    printf("\t\t\t\t    3.退出\n");
    printf("----------------------------------------------\n");
    printf("請選擇你想要進行的操作:");
           

繼續閱讀