查找相关
一、 实验目的
掌握顺序表的查找;
掌握哈希存储结构的思想,能选择合适的哈希函数,实现不同冲突处理方法的哈希表的查找、建立。
二、 实验内容及要求
(1) 顺序表的顺序查找
(2) 有序顺序表的二分查找的递归算法与非递归算法
(3) 哈希表查找
a) 设计哈希函数及处理冲突的方法;
b) 键盘输入数据,利用设计的哈希函数及线性探测法生成哈希表;
c) 用同样的输入数据和哈希函数,用链地址法处理冲突生成哈希表;
d) 在主函数中设计一个简单的菜单,分别调试上述算法;
(4)
(5)分析两种方法的平均查找长度。
ShunXuAndHash.h
#ifndef DACM_ZSN_SHUNXUBIAOCHAZHAO_H
#define DACM_ZSN_SHUNXUBIAOCHAZHAO_H
#define MaxSize 100 //表中元素的最大个数
typedef int ElemType; //元素类型
typedef int KeyType;
typedef struct {
ElemType *elem; //线性表
int length; //表的实际长度
int listsize; //当前分配的存储容量
} SqList; //顺序表的类型名
int InitList(SqList &L, int n);/*初始化顺序表*/
void CreateList(SqList &L);/*建立顺序表*/
void PrintList_Sq(SqList L);/*输出顺序表*/
typedef int KeyType;
typedef int IndoType;
typedef struct{
int *elem;//数据元素存储地址,动态分配数组
int count; //当前数据元素个数
}HashTable;
#define NULLKEY1 -1
void LianDiZhi();
void XianXingTanCe();
int SearchHash(HashTable *HT,int data,int HASHSIZE);
void SearchTest(int HASHSIZE);
int Hash(int data,int HASHSIZE);
void Init(HashTable *hashTable,int HASHSIZE);
#endif //DACM_ZSN_SHUNXUBIAOCHAZHAO_H
ShunXuAndHash.cpp
#include "ShuXuAndHash.h"
#include<bits/stdc++.h>
#include<stdlib.h>
using namespace std;
//初始化顺序表
int InitList(SqList &L, int n) {
L.elem = (ElemType *) malloc(n * sizeof(ElemType));
if (!L.elem) return 0;
L.length = 0;
L.listsize = n;
return 1;
}
/*建立顺序表*/
void CreateList(SqList &L) {
int i;
printf("输入表的长度:");
scanf("%d", &L.length);//输入表长
printf("请输入%d个数", L.length);
for (i = 1; i <= L.length; i++)
scanf("%d", &L.elem[i - 1]);//输入元素
}
int ListInsert(SqList &L, ElemType e) // 插入数据
{
//先判断是否已满
int i, j;
if (L.length == L.listsize) {
return -1;
} else {
i = L.length - 1;
while (i >= 0 && e < L.elem[i]) {
i--;
}
for (j = L.length - 1; j >= i + 1; j--) {//从最后一个元素开始向后移动一个位置
L.elem[j + 1] = L.elem[j];
}
L.elem[i + 1] = e;
L.length++;
return 0;
}
}
//建立递增有序的顺序表
void CreateList_Sorted(SqList &L) {
int i, num;
ElemType e;
L.length = 0;
printf("建立递增有序的顺序表,请输入数据个数:\n");
scanf("%d", &num);
printf("请输入%d个数据:\n", num);
for (i = 1; i <= num; i++) {
scanf("%d", &e);
ListInsert(L, e);
}
}
/*建立顺序表*/
int CreateList_Sq(SqList &L) {
int n, i;
printf("请输入顺序表长度:");
scanf("%d", &n);
if (InitList(L, n)) {
printf("请输入%d个元素:", n);
for (i = 0; i < n; i++) {
scanf("%d", &L.elem[i]);
L.length++;
}
return 1;
} else
return 0;
}
/*输出顺序表*/
void PrintList_Sq(SqList L) {
int i;
printf("顺序表中元素为:\n");
for (i = 0; i < L.length; i++) {
printf("%d ", L.elem[i]);
}
printf("\n");
}
//顺序查找
int ShunXu(SqList L, ElemType e) {
int i;
for (i = 0; i < L.length; i++)
if (*(L.elem + i) == e)
return i;
return -1;
}
//有序表的二分查找
int ZheBanFeiDiGui(SqList L, ElemType key) {
int low = 0, high = L.length - 1, mid;
while (low < high) {
mid = (low + high) / 2;
if (L.elem[mid] == key) {
return mid;
} else if (L.elem[mid] > key) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return -1;
}
//折半查找递归
int ZheBanDiGui(SqList L, int low, int high, KeyType K)//递归法
{//在 A[low] ~ A[high]区间进行查找,low、high初值分别为 0 和 n-1
if (low <= high) {
int mid = (low + high) / 2; //求中点元素下标
if (K == L.elem[mid])
return mid;
else if (K < L.elem[mid])
return ZheBanDiGui(L, low, mid - 1, K);
else
return ZheBanDiGui(L, mid + 1, high, K);
} else
return -1; //查找失败
}
//哈希查找
//int SearchHash(HashTable HT,KeyType){
// H0=H(key);
// if(HT[H0].key==NULLKEY)return -1;
// if (HT[H0].key==key) return H0;
// for (int i = 1; i < m; ++i) {
// Hi=(H0+i)%m;
// if (HT[Hi].key==NULLKEY)return -1;
// if (HT[Hi].key==key)return Hi;
// }
// return -1;
//}
//哈希函数(除留余数法)
void menu() {
printf("\t选择:\n");
printf("1.顺序表的顺序查找\n");
printf("2.顺序表的二分查找(递归和非递归)\n");
printf("3.哈希查找\n");
printf("0.退出\n");
}
int Hash(int data, int HASHSIZE) {
return data % HASHSIZE;
}
void Init(HashTable *hashTable, int HASHSIZE) {
int i;
hashTable->elem = (int *) malloc(HASHSIZE * sizeof(int));
hashTable->count = HASHSIZE;
for (i = 0; i < HASHSIZE; i++) {
hashTable->elem[i] = NULLKEY1;
}
}//12 19 32 1 20 37 83 9 3 54 7 89 -1
//哈希表的插入函数,可用于构造哈希表
void Insert(HashTable *hashTable, int data, int HASHSIZE) {
int hashAddress = Hash(data, HASHSIZE); //求哈希地址
//发生冲突
while (hashTable->elem[hashAddress] != NULLKEY1) {
//利用开放定址法解决冲突
++hashAddress;
hashAddress %= HASHSIZE;
}
hashTable->elem[hashAddress] = data;
}
int SearchHash(HashTable *hashTable, int data, int HASHSIZE) {
int hashAddress = Hash(data, HASHSIZE); //求哈希地址
while (hashTable->elem[hashAddress] != data) {//发生冲突
//利用开放定址法解决冲突
++hashAddress;
hashAddress %= HASHSIZE;
//如果查找到的地址中数据为NULL,或者经过一圈的遍历回到原位置,则查找失败
if (hashTable->elem[hashAddress] == NULLKEY1 || hashAddress == Hash(data, HASHSIZE)) {
return -1;
}
}
return hashAddress;
}
void SearchTest(int HASHSIZE) {
int i = 0, result, data,flag=0;
HashTable HT;
int *arr = NULL;
printf("请输入元素(-1结束)且数量不大于%d:", HASHSIZE);
arr = (int *) malloc(sizeof(int) * HASHSIZE);
while (1) {
scanf("%d", &arr[i]);
flag=flag>arr[i]?flag:arr[i];
if (arr[i] == -1) {
arr[i] = 0;
break;
}
i++;
}
//初始化哈希表
// int arr[HASHSIZE]={13,29,27,28,26,30,38};
Init(&HT, HASHSIZE);
//利用插入函数构造哈希表
for (i = 0; i < HASHSIZE; i++) {
Insert(&HT, arr[i], HASHSIZE);
}
for (int j = 0; j < HASHSIZE; ++j) {
if (HT.elem[j]>flag||(j>0&& HT.elem[j]==0)) HT.elem[j]=-1;
printf("%d\t", HT.elem[j]);
}printf("\n");
printf("请输入需要查找的数: ");
scanf("%d", &data);
result = SearchHash(&HT, data, HASHSIZE);
if (result == -1)
printf("查找失败\n");
else
printf("%d在哈希表中的位置是:%d\n", data, result);
}
void XianXingTanCe() {
printf("请输入序列数量:n和余数:p\n");
int i, n, *a, p;
HashTable hashTable;
//double k;
scanf("%d%d", &n, &p);
//L = (int)(1.0*n / k);
a = (int *) malloc((n + 9) * sizeof(int));
hashTable.elem = (int *) malloc((p + 9) * sizeof(int));
printf("然后输入%d个数:\n", n);
for (i = 1; i <= n; i++)
scanf("%d", &a[i]);
int sum = 0;
for (i = 0; i <= p; i++) hashTable.elem[i] = -1;
for (i = 1; i <= n; i++) {
int key = a[i] % p, num = 1;
while (hashTable.elem[key] != -1) {
num++;
key = (key + 1) % p;
}
sum += num;
hashTable.elem[key] = a[i];
}
printf("散列表\n");
for (i = 0; i < p; i++)
printf("%d%c", hashTable.elem[i], (i == p - 1) ? '\n' : ' ');
printf("平均查找长度(成功)\n");
if (sum % n == 0)
printf("%d\n", sum / n);
else {
int g = __gcd(sum, n);
printf("%d/%d\n", sum / g, n / g);
}
}
void LianDiZhi() {
printf("请输入序列数量:n和余数:p:\n");
int n, i, j, *a, p;
HashTable hashTable;
hashTable.elem = (int *) malloc(sizeof(int) << 7);
hashTable.elem[0] = 0;
for (i = 1; i <= 100; i++)
hashTable.elem[i] = hashTable.elem[i - 1] + i;
scanf("%d%d", &n, &p);
a = (int *) malloc((n + 9) * sizeof(int));
vector<int> mp[n + 9];
printf("然后输入%d个数:\n", n);
for (i = 1; i <= n; i++) scanf("%d", &a[i]);
int sum = 0;
for (i = 1; i <= n; i++) {
int key = a[i] % p;
mp[key].push_back(a[i]);
}
printf("散列表\n");
for (i = 1; i <= n; i++) {
int num = mp[i].size();
for (j = 0; j < num; j++)
printf("%d%c", mp[i][j], (j == num - 1) ? '\n' : ' ');
sum += hashTable.elem[num];
}
printf("平均查找长度(成功)\n");
if (sum % n == 0)
printf("%d\n", sum / n);
else {
int g = __gcd(sum, n);
printf("%d/%d\n", sum / g, n / g);
}
}
int main() {
while (1) {
menu();
int choice = 0;
int loc, key1, key2;
int sel;
int HASHSIZE;
scanf("%d", &choice);
switch (choice) {
case 1:
SqList L1;
InitList(L1, 100);
CreateList(L1);
PrintList_Sq(L1);
printf("请输入需要查找的值:\n");
scanf("%d", &key1);
loc = ShunXu(L1, key1);
if (loc == -1) printf("表中不存在%d\n", key1);
else printf("%d在表中的位置是:%d\n", key1, loc);
break;
case 2:
SqList L2;
InitList(L2, 100);
CreateList_Sorted(L2);
PrintList_Sq(L2);
printf("请输入需要查找的值:");
scanf("%d", &key2);
printf("1.递归:\n");
loc = ZheBanDiGui(L2, 0, L2.length, key2);
if (loc == -1) printf("表中不存在%d\n", key2);
else printf("%d在表中的位置是:%d\n", key2, loc);
printf("2.非递归:\n");
loc = ZheBanFeiDiGui(L2, key2);
if (loc == -1) printf("表中不存在%d\n", key2);
else printf("%d在表中的位置是:%d\n", key2, loc);
break;
case 3:
printf("\t1.哈希函数及线性探测法生成哈希表\n");
printf("\t2.链地址法处理冲突生成哈希表\n");
printf("\t3.Hash查找表中具体数据\n");
printf("\t4.退出\n");
scanf("%d", &sel);
switch (sel) {
case 1:
XianXingTanCe();
break;
case 2:
LianDiZhi();
break;
case 3:
printf("请输入Hash表大小:");
scanf("%d", &HASHSIZE);
SearchTest(HASHSIZE);
break;
case 4:
if (sel == 3) return 0;
else break;
}
case 0:
if (choice == 0) return 0;
else break;
}
}
}
生命依靠吸收负熵,避免了趋向平衡的衰退