目录
原理:
实例解释
存储逻辑图
需要的知识:
附加
完整代码
代码详解
执行结果
1.查找个不存在的
2.查找个存在的
用一个指针数组,来存储 每个链表的头节点 的首地址
如果要从 'NUM' 个数中查找数据
先对'NUM'/0.75,求得最大质数'N' //(质数:只能被1和本身整除的数)
然后创建一个有'N'个元素的'指针数组'
然后将'NUM'个数分别对'N'取余
将每一个数保存在'余数'等于数组元素下标的链表中
然后进行查找是直接找对应的数组下标即可
如果要从11个数中查找数据
然后11/0.75=14,求得最大质数13
然后创建一个有13个元素的'指针数组'
然后将'11个数'分别对'13取余'
将每一个数保存在'余数'等于'数组元素下标'的链表中 //---需要链表
然后进行查找是直接找对应的数组下标即可
质数:只能被1和本身整除的数
指针数组:本质是个数组,数组里存的是指针
链表的操作:
创建:
遍历:
增删改查:
释放:free
malloc:主动申请堆区空间 //(返回值类型)malloc(申请的空间的大小)
int类型:4个字节
指针类型:4个字节(32位系统),8个字节(64位系统)
哈希表查找算法的时间复杂度为O(n^1)
HASH查找效率高的原因:
查找某一个数,先求出这个数的余数,然后根据余数直接定位到对应的链表地址,然后在该链表里查找(链表里只有几个数据)--所以快!!
#include
#include
#define N 13
#define ADDR_SIZE 8
//hash表的链表的节点
typedef struct node {
int data;//存数据
struct node *next;//存指针
}HASH;
//创建hash表
HASH **create_hash()
{
HASH **h = (HASH **)malloc(N * ADDR_SIZE);
int i = 0;
for (i = 0; i < N; i++)
{
h[i] = (struct node *)malloc(sizeof(struct node));
h[i]->next = NULL;
}
return h;
}
//插入数据
int insert_hash_table(HASH **h, int data)
{
int key = data % N;
struct node * p = h[key];
//头插法插入数据
struct node * temp;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = data;
temp->next = p->next;
p->next = temp;
return 0;
}
//遍历
int show_hash_table(struct node *head)
{
//如果链表后面没有数据,则用---0---表示链表存在但是没有数据
if (head->next == NULL)
{
puts("---0---");
return -1;
}
//遍历链表,打印数据
while(head->next != NULL)
{
head = head->next;
printf("%d ", head->data);
}
putchar(10);
return 0;
}
//释放链表节点
int free_hash_table(struct node *head)
{
//如果链表后面没有数据,则无需释放
if (head->next == NULL)
{
return 0;
}
//遍历这个链表-头删法释放
while(head->next != NULL)
{
//定义一个结构体指针变量 来指向这个即将被删除的结构体 以便释放
struct node *temp = head->next;
head->next = head->next->next;
printf("--%d--将被释放\n",temp->data);
free(temp);
temp = NULL;
}
return 0;
}
//查找数据
int search_hash_table(HASH **h, int data)
{
int key = data % N; //数据对质数取余,得到键值
struct node *p = h[key]; //找到对应链表
//对比要查找的数据
while (p->next != NULL )
{
if (p->next->data == data)
{
return 1;//找到返回1
}
p = p->next;
}
//没有找到返回0
return 0;
}
//11个数据,那么m : n/0.75 = 14, 最大质数为13
int main(int argc, const char *argv[])
{
int a[11] = {100, 34, 14, 45, 46, 98, 68, 69, 7, 31, 26};
//创建hash表
HASH **h = create_hash();
int i = 0;
int num = 0;
for (i = 0; i < 11; i++)
{
insert_hash_table(h, a[i]);//链表的插入
}
//打印hash表--无实际意义
printf("-------这是hash表--------------------\n");
for (i = 0; i < N; i++)
{
show_hash_table(h[i]);//链表的遍历
}
printf("--------hash表结束--------------------\n");
printf("数组数据如下-->用于测试,无实质意义,遍历HASH表也是<---\n");
for(i = 0;i < 11;i ++)
{
printf("%d ",a[i]);
}
putchar(10);
printf("please input need 查找 de number >>");
scanf("%d",&num);
//--查找--
if(search_hash_table(h, num) == 1)
{
printf("---data %d is exists---\n", num);
}
else
{
printf("---data %d is not exists---\n", num);
}
//链表的释放
for(i = 0;i < 11;i ++)
{
free_hash_table(h[i]);
}
printf("---链表释放完成---\n");
free(h);
printf("---指针数组释放---\n");
return 0;
}
#include
#include
#define N 13 //余数:也是指针数组的元素个数:也是链表的个数
#define ADDR_SIZE 8 //这个定义的是 指针数组的 每个指针的大小,(64位系统)8个字节
//hash表 链表的节点
typedef struct node {
int data;//存数据
struct node *next;//存指针
}HASH;//类型重命名-->HASH
//创建hash表(创建了十三个链表头节点)
HASH **create_hash()
{
//申请创建一个指针数组,存13个头节点
//先创建一个指针数组,指针数组可以在栈区申请(int *h[]),但是当前函数结束会被释放
//所以在堆区申请空间,指针数组的返回值 是二级指针 所以用HASH **h来接收
//这块申请了一个 有13个位置的指针数组
HASH **h = (HASH **)malloc(N * ADDR_SIZE);//(返回值类型)malloc(申请的空间的大小)
int i = 0;
//这块要填充这个指针数组
//创建链表的头结点--先malloc申请出来一个头节点,分别把他们放到指针数组h[0]--h[12] 里
for (i = 0; i < N; i++)
{
h[i] = (struct node *)malloc(sizeof(struct node));//创建头节点
h[i]->next = NULL;//初始化头节点 指针域
} //注意:再此申请的节点 都被保存到 (指针数组)h 里了
return h;
}
//插入数据
int insert_hash_table(HASH **h, int data)//参数:指针数组,需要插入的数据
{
//然后将'需要插入的数据'对'质数13取余'--确定好数据对应的 指针数组下标
//找到指定的链表
int key = data % N;
//根据指针数组的下标,确定对应的链表的头节点,
//定义了一个结构体指针变量p 指向 指针数组的第[key]位对应的 链表
struct node *p = h[key];//也可以直接操作h[key],定义一个指针好理解点
//--头插法--插入数据
struct node *temp;//定义了一个 结构体指针变量
temp = (struct node *)malloc(sizeof(struct node));//malloc申请空间
temp->data = data;//初始化一下
//头插法 插入
temp->next = p->next;//新定义节点的指针域 指向 头节点的下一个节点
p->next = temp;//头节点的指针域,指向新定义的节点
return 0;
}
//打印排好的hash表--遍历
int show_hash_table(struct node *head)//参数:对应链表的头节点--main函数多次调用
{
//如果链表后面没有数据,则用---0---表示链表存在但是没有数据
if (head->next == NULL)
{
puts("---0---");
return -1;
}
//如果链表后面有数据,遍历链表,打印数据
while(head->next != NULL)
{
//由于头节点没有数据,所以,先移动指针,然后输出数据
head = head->next;
printf("%d ", head->data);
}
putchar(10);//输出个换行符
return 0;
}
//释放链表节点
int free_hash_table(struct node *head)
{
//如果链表后面没有数据,则无需释放
if (head->next == NULL)
{
return 0;
}
//遍历这个链表-头删法释放
while(head->next != NULL)
{
//定义一个结构体指针变量 来指向这个即将被删除的结构体 以便释放
struct node *temp = head->next;
head->next = head->next->next;//改变头结点指针域指向,删除节点
printf("--%d--将被释放\n",temp->data);
free(temp);//释放
temp = NULL;//置空(防止被别的函数修改)
}
return 0;
}
//查找数据
int search_hash_table(HASH **h, int data)//参数:指针数组,需要查找的数据
{
int key = data % N; //先把要查找的数据对 质数 取余,得到对应的下标
struct node *p = h[key]; //根据下标找到对应链表,定义了一个结构体指针变量p,指向该链表
//--循环遍历--对比--
//循环遍历的结束条件是,p->next 域 为空(NULL)
while (p->next != NULL)
{
if (p->next->data == data)
{
return 1;//找到返回1
}
p = p->next;//移动指针
}
//没有找到返回0
return 0;
}
//程序的入口:
//假定数组有11个元素--> 11/0.75 ==> 14.67 ==> 最大质数 为 13
int main(int argc, const char *argv[])
{
int a[11] = {100, 34, 14, 45, 46, 98, 68, 69, 7, 31, 26};
//直接初始化了11个数值的数组
//创建hash表
HASH **h = create_hash();//为啥用二级指针:指针数组的返回值是二级指针
//将数据按照格式插入到链表中
int i = 0;
int num = 0;
//链表增加--多次调用-插入数组a的每个元素
for (i = 0; i < 11; i++)//给 a[i] 使的
{
insert_hash_table(h, a[i]); //链表的插入
}
printf("-------这是hash--------------------\n");
//打印hash表--打印每个指针数组元素所存储的链表
for (i = 0; i < N; i++)
{
show_hash_table(h[i]);//链表的遍历
}
printf("--------hash表结束--------------------\n");
printf("数组数据如下-->用于测试,无实质意义,遍历HASH表也是<---\n");
for(i = 0;i < 11;i ++)
{
printf("%d ",a[i]);
}
putchar(10);
// while(1)
// {
//查找
printf("please input need 查找 de number >>");
scanf("%d",&num);
//由于输入字母,会造成死循环,所以也可以用char类型定义,或者加个判断(ASCII码)
//指定数据判断是否存在-----查找
if(search_hash_table(h, num) == 1)
{
printf("---data %d is exists---\n", num);
}
else
{
printf("---data %d is not exists---\n", num);
}
// }
//链表的释放
for(i = 0;i < 11;i ++)
{
free_hash_table(h[i]);
}
printf("---链表释放完成---\n");
free(h);
printf("---指针数组释放---\n");
return 0;
}