下载
<1>.散列表
散列表也叫哈希表。以数组结构来作对比,数组中要查询某一个值,得通过一个一个数值的比较。而hashtable是通过某一种关系(func)的映射:【key,value】:
存储地址 = func(关键字)
也就是一种键值关系。找到存储地址,就相当于找到值了,而不像数组需要去比较。实现这样一种对应关系有多种算法。这里以求余数算为例。
存储地址=func(key)=key mod m(p《= m)
m:是散列表长度。
<2>.冲突:
不同的关键字对应同一个存储地址。
本例开放定址法:
例如:买房子,看到价格适中的房子,地段各方面又好的,准备下手,结果被人家抢先了。你怎么办呢?找还没有卖掉的下一家。这也就开明,开放的思想。本例使用此方法。
例子: int nums[12] = {12,67,56,16,25,37,22,29,15,47,48,34};
地址/数组下标 :key
0 :12
1 :25
2 :
3 :
4 :16
5 :
6 :
7 :67
8 :56
9 :
10 :
11 :
当存储37(37%12=1)在“1”下标的位置,这就是冲突,然后以开放的心态,那就存在“2”的位置。就这样了。
另一种是解决冲突的方法,linux用到的:
冲突的值放在同一个键下面,多个元素作单链表。查询相同的键时,使用第二特征区别相同键下面的元素。
注:本书来自《大话数据结构》,只是使用来学习,理解,实践。
[root@localhost test]# pwd
/root/桌面/test
[root@localhost test]# ls
data.c data.h hashtable.c hashtable.h main.c
[root@localhost test]# gcc -o main main.c hashtable.c data.c
[root@localhost test]# ls
data.c data.h hashtable.c hashtable.h main main.c
[root@localhost test]#
hashtable.h:
#ifndef __HASH_TABLE__
#define __HASH_TABLE__
#define SUCCESS 1
#define UNSUCCESS 0
#define HASHSIZE 12 /*定义散列表的长为数组的长度*/
#define NULLKEY -32768
typedef struct
{
int *elem; /*数据元素存储基地址,动态分配数组*/
int count; /*当前数据元素个数*/
}HashTable;
int InitHashTable(HashTable *H);
int Hash(int key);
void InsertHash(HashTable *H, int key);
int SearchHash(HashTable H, int key, int *addr);
#endif
hashtable.c:
#include <stdlib.h>
#include <stdio.h>
#include "hashtable.h"
#include "data.h"
/*初始化散列表*/
int InitHashTable(HashTable *H)
{
int i;
m = HASHSIZE;
H->count = m;
H->elem = (int *)malloc(m * sizeof(int));
for (i = 0;i<m;i++)
H->elem[i] = NULLKEY;
return SUCCESS;
}
/*散列函数*/
int Hash(int key)
{
return key % m; /*除留余数法*/
}
/*插入关键字进行散列表*/
void InsertHash(HashTable *H, int key)
{
int addr = Hash(key);/*通过散列函数,求散列地址*/
while(H->elem[addr] != NULLKEY) /*如果不为空,则冲突*/
addr = (addr + 1) % m; /*开放定址法的线性探测*/
H->elem[addr] = key; /*直到有空位后插入关键字*/
printf("key:%d, addr:%d, elem:%d\n", key, addr, H->elem[addr]);
}
/*散列表查找关键字*/
int SearchHash(HashTable H, int key, int *addr)
{
*addr = Hash(key); /*求散列地址*/
while(H.elem[*addr]!= key) /*如果不为空,则冲突*/
{
*addr = (*addr + 1) % m; /*开放定址法的线性探测*/
if (H.elem[*addr] == NULLKEY || *addr == Hash(key))
{/*如果循环回到原点*/
return UNSUCCESS; /*则说明关键字不存在*/
}
}
return SUCCESS;
}
data.h
#ifndef __DATA__
#define __DATA__
extern m;
#endif
data.c
int m = 0; /*散列表表长,全局变量*/
main.c
#include <stdio.h>
#include "hashtable.h"
#include "data.h"
int main()
{
int i = 0, lennums = 0;
int nums[12] = {12,67,56,16,25,37,22,29,15,47,48,34};
int addrresult = 0;
HashTable hasht;
InitHashTable(&hasht);
printf("count= %d ,size-nums = %d\n", hasht.count, sizeof(nums)/sizeof(int));
lennums = sizeof(nums)/sizeof(int);
/*使用查询检测一下*/
for (i = 0; i < lennums; i++)
{
SearchHash(hasht, nums[i], &addrresult);
printf("elem :%d addr is :%d\n",nums[i],addrresult);
}
return 0;
}
输出结果:
[root@localhost test]# ls
data.c data.h hashtable.c hashtable.h main main.c
[root@localhost test]# ./main
count= 12 ,size-nums = 12
elem :12 addr is :1
elem :67 addr is :8
elem :56 addr is :9
elem :16 addr is :5
elem :25 addr is :2
elem :37 addr is :2
elem :22 addr is :11
elem :29 addr is :6
elem :15 addr is :4
elem :47 addr is :0
elem :48 addr is :1
elem :34 addr is :11
[root@localhost test]#