您的位置:首页 > 其它

《算法导论》第十一章----散列表(直接寻址、链接法解决碰撞)

2013-10-27 23:29 330 查看

《算法导论》第十一章----散列表(直接寻址、链接法解决碰撞)

《算法导论》学习记录目录

散列表(哈希表)是根据关键字直接访问内存存储位置的数据结构,仅支持插入、查找、删除操作。在最坏情况下,查找一个元素的时间为Θ(n),而在一些合理的假设下,查找一个元素的期望时间为O(1)。

散列表是普通数组的推广。对于普通数组:

    1、我们可以将关键字为k的元素存到数组下标为k的位置里。

    2、如果有一个关键字k,我们直接查看数组下标为k的位置。

这种方式为直接寻址方式。但是这种方式有不足:只适用于关键字的全域比较小,而且没有两个元素的关键字完全相同。而显示中存储的关键字集合会比关键字的全域相对小很多。

下图为直接寻址表:

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

#define MAX 6

typedef struct {
int key;
int satellite;
}Data; //元素结构体,有关键字和卫星数据

Data* direct_address_search(Data *T[], int key); //散列表查找操作

void direct_address_insert(Data *T[], Data *x); //散列表插入操作

void direct_address_delete(Data *T[], Data *x); //散列表删除操作

void print_table(Data *T[]); //打印散列表(为了方便查看删除操作后,散列表的变化)

int main(){
int i, num, key, satellite;
Data *data[MAX];
for(i = 0; i < MAX; i++){
data[i] = (Data *)malloc(sizeof(Data));
data[i] = NULL;
}

for(i = 0; i <= 3; i++){
Data *d = (Data *)malloc(sizeof(Data));
printf("Input the key_value:\n");
scanf("%d", &key)=;
printf("Input the satellite:\n");
scanf("%d", &satellite);
d->key = key;
d->satellite = satellite;
direct_address_insert(data, d);
}
print_table(data);
key = 3;
Data *d = direct_address_search(data, key);
printf("the key is %d, and its satellite is %d\n", d->key, d->satellite);

direct_address_delete(data, d);
print_table(data);
return 0;
}

/*
*直接返回下标为key的元素
*/
Data* direct_address_search(Data *T[], int key){
return T[key];
}

/*
* 直接将元素插入下标key的位置里
*/
void direct_address_insert(Data *T[], Data *x){
T[x->key] = x;
}

/*
* 将要删除的元素所在的位置指向空指针
*/
void direct_address_delete(Data *T[], Data *x){
T[x->key] = NULL;
}

/*
* 打印直接寻址表
*/
void print_table(Data *T[]){
int i;
for(i = 0; i < MAX; i++){
if(T[i] != NULL){
printf("key is %d, and its satellite is %d\n", T[i]->key, T[i]->satellite);
}
}
}

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

#define MAX 10
typedef struct {
int key;
int satellite;
}Data; //元素结构体,有关键字和卫星数据

typedef struct ListNode {
Data data;
struct ListNode * next;
struct ListNode * prev;
}ListNode; //双链表结点结构体,存储的数据为元素,前后指针

typedef struct {
ListNode *List[MAX];
}Hash_table; //散列表结构体,双链表数组

int hash_function(int n); //散列函数

void list_insert(ListNode *l, Data d); //链表插入

int list_search(ListNode *l, int key); //链表查找

int list_delete(ListNode *l, Data d); //链表删除

void print_list(ListNode *l); //打印链表

void chained_hash_insert(Hash_table *T, Data x); //散列表插入,基于链表插入

int chained_hash_delete(Hash_table *T, Data x); //散列表删除,基于链表删除

int chained_hash_search(Hash_table *T, int key); //散列表查找,基于链表查找

void print_table(Hash_table *T); //打印散列表,基于打印链表

int main(){
int i, num, key, satellite;
Data dd;
Hash_table *ht = (Hash_table *)malloc(sizeof(Hash_table));
for(i = 0; i < MAX; i++){
ht->List[i] = (ListNode *)malloc(sizeof(ListNode));
ht->List[i]->next = NULL;
}

for(i = 0; i < 15; i++){
Data d;
printf("Input the key:\n");
scanf("%d", &key);
printf("Input the satellite:\n");
scanf("%d", &satellite);
d.key = key;
d.satellite = satellite;
chained_hash_insert(ht, d);

if(i == 14){
dd.key = d.key;
dd.satellite = d.satellite;
}
}

key = 3;
printf("Does %d in the table?\n", key);
if(chained_hash_search(ht, key))
printf("Yes!\n");
else
printf("No!\n");

printf("Delete the last input element!\n");
chained_hash_delete(ht,dd);

print_table(ht);
return 0;
}

/*
* 散列函数为直接将n对散列表大小取余
*/
int hash_function(int n){
return n % 10;
}

void list_insert(ListNode *l, Data d){
ListNode *p;
p = (ListNode *)malloc(sizeof(ListNode));
p->data = d;

if(l->next == NULL){
l->next = p;
p->prev = l;
p->next = NULL;
}
else{
l->next->prev = p;
p->next = l->next;
l->next = p;
p->prev = l;
}
}

int list_search(ListNode *l, int key){
ListNode *p = l->next;

while(p != NULL){
if(p->data.key == key)
return 1;
p = p->next;
}

return 0;
}

int list_delete(ListNode *l, Data d){
ListNode *p = l->next;

while(p != NULL){
if(p->data.key == d.key){
p->prev->next = p->next;
p->next->prev = p->prev;

free(p);
return 1;
}
p = p->next;
}
return 0;
}

void print_list(ListNode *l){
ListNode *p = l->next;

while(p != NULL){
printf("\tKey: %d, Satellite: %d", p->data.key, p->data.satellite);
p = p->next;
}
printf("\n");
}

void chained_hash_insert(Hash_table *T, Data d){
list_insert(T->List[hash_function(d.key)], d);
}

int chained_hash_delete(Hash_table *T, Data d){
return list_delete(T->List[hash_function(d.key)], d);
}

int chained_hash_search(Hash_table *T, int key){
return list_search(T->List[hash_function(key)], key);
}

void print_table(Hash_table *T){
int i;
for(i = 0; i < MAX; i++){
printf("Row %d in Table: ", i);
print_list(T->List[i]);
}
}

1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #define MAX 10
5 typedef struct {
6     int key;
7     int satellite;
8 }Data;                      //元素结构体,有关键字和卫星数据
9
10 typedef struct ListNode {
11     Data data;
12     struct ListNode * next;
13     struct ListNode * prev;
14 }ListNode;                  //双链表结点结构体,存储的数据为元素,前后指针
15
16 typedef struct {
17     ListNode *List[MAX];
18 }Hash_table;                //散列表结构体,双链表数组
19
20 int hash_function(int n);       //散列函数
21
22 void list_insert(ListNode *l, Data d);  //链表插入
23
24 int list_search(ListNode *l, int key);  //链表查找
25
26 int list_delete(ListNode *l, Data d);   //链表删除
27
28 void print_list(ListNode *l);           //打印链表
29
30 void chained_hash_insert(Hash_table *T, Data x);    //散列表插入,基于链表插入
31
32 int chained_hash_delete(Hash_table *T, Data x);     //散列表删除,基于链表删除
33
34 int chained_hash_search(Hash_table *T, int key);    //散列表查找,基于链表查找
35
36 void print_table(Hash_table *T);                    //打印散列表,基于打印链表
37
38 int main(){
39     int i, num, key, satellite;
40     Data dd;
41     Hash_table *ht = (Hash_table *)malloc(sizeof(Hash_table));
42     for(i = 0; i < MAX; i++){
43         ht->List[i] = (ListNode *)malloc(sizeof(ListNode));
44         ht->List[i]->next = NULL;
45     }
46
47     for(i = 0; i < 15; i++){
48         Data d;
49         printf("Input the key:\n");
50         scanf("%d", &key);
51         printf("Input the satellite:\n");
52         scanf("%d", &satellite);
53         d.key = key;
54         d.satellite = satellite;
55         chained_hash_insert(ht, d);
56
57         if(i == 14){
58             dd.key = d.key;
59             dd.satellite = d.satellite;
60         }
61     }
62
63     key = 3;
64     printf("Does %d in the table?\n", key);
65     if(chained_hash_search(ht, key))
66         printf("Yes!\n");
67     else
68         printf("No!\n");
69
70     printf("Delete the last input element!\n");
71     chained_hash_delete(ht,dd);
72
73     print_table(ht);
74     return 0;
75 }
76
77 /*
78  * 散列函数为直接将n对散列表大小取余
79  */
80 int hash_function(int n){
81     return n % 10;
82 }
83
84 void list_insert(ListNode *l, Data d){
85     ListNode *p;
86     p = (ListNode *)malloc(sizeof(ListNode));
87     p->data = d;
88
89     if(l->next == NULL){
90         l->next = p;
91         p->prev = l;
92         p->next = NULL;
93     }
94     else{
95         l->next->prev = p;
96         p->next = l->next;
97         l->next = p;
98         p->prev = l;
99     }
100 }
101
102 int list_search(ListNode *l, int key){
103     ListNode *p = l->next;
104
105     while(p != NULL){
106         if(p->data.key == key)
107             return 1;
108         p = p->next;
109     }
110
111     return 0;
112 }
113
114 int list_delete(ListNode *l, Data d){
115     ListNode *p = l->next;
116
117     while(p != NULL){
118         if(p->data.key == d.key){
119             p->prev->next = p->next;
120             p->next->prev = p->prev;
121
122             free(p);
123             return 1;
124         }
125         p = p->next;
126     }
127     return 0;
128 }
129
130 void print_list(ListNode *l){
131     ListNode *p = l->next;
132
133     while(p != NULL){
134         printf("\tKey: %d, Satellite: %d", p->data.key, p->data.satellite);
135         p = p->next;
136     }
137     printf("\n");
138 }
139
140
141 void chained_hash_insert(Hash_table *T, Data d){
142    list_insert(T->List[hash_function(d.key)], d);
143 }
144
145 int chained_hash_delete(Hash_table *T, Data d){
146    return list_delete(T->List[hash_function(d.key)], d);
147 }
148
149 int chained_hash_search(Hash_table *T, int key){
150     return list_search(T->List[hash_function(key)], key);
151 }
152
153 void print_table(Hash_table *T){
154     int i;
155     for(i = 0; i < MAX; i++){
156         printf("Row %d in Table: ", i);
157         print_list(T->List[i]);
158     }
159 }


链接法散列的最坏情况下运行时间为:Θ(n),所有关键字都散列到同一个位置上,就相当于在一个链表上进行查找。

散列方法的平均性能依赖于所选取的散列函数在一般情况下将所有的关键字分布在散列表的位置上的均匀程度。

简单一致性散列:假设任何元素散列到长度为m的散列表中的每一个位置的可能性都是相同的,且和其他已被散列到什么位置上是无关的。

对于n个数据,在长度为m的散列表上,每个为位置的链表长度为a, a=n/m。

在简单一致性散列的假设下,在用链接法的散列表上的一次不成功的查找的期望时间为Θ(1+a)。

因为链表的平均长度为a,一次不成功查找平均检查a个元素,再加上计算该元素的散列值的总时间为Θ(1+a)。

对于如何设计好的散列函数,有两种方法:启发式(除法进行散列和乘法进行散列)、随机化(全域散列)。

除法散列法的散列函数为: h(k) = k mod m 。m的取值应该为与2的整数幂不太接近的质数。

乘法散列法的散列函数为: h(k) = floor(m(k * A mod 1)) 。其中k * A mod 1 为k * A 的小数部分, A 为小数。Knuth大神认为A 应该约等于√5 - 1 。。。

全域散列的散列函数为在散列函数组里随机选择散列函数。。。。。。。

PS:书中有很多理论的东西都看不懂。。。。。。。继续努力。。。。该文章会继续更新!!!特别是开放寻址法。。。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: