数据类型之哈希

-- Start

学过 Java 的人应该对 hash 不陌生,所谓 hash 就是存储一对 key 和 value 的一种数据结构,它用来存储一种对应关系,如:省份证号和姓名,IP 地址和域名等等。在 Perl 中,key 必须是字符串,value 可以是任何标量。下面的例子演示如何使用hash。

#!/usr/bin/perl

%IDForName; # 空hash
%IDForName = (); # 空hash


%IDForName = ('1', '张三', '2', '李四'); # 将列表中的值赋给hash
%IDForName = ('1'=>'张三', '2'=>'李四'); # => 相当于逗号,使用上和逗号没有任何区别


@people = ('1', '张三', '2', '李四');
%IDForName = @people; # 将数组中的值赋给hash
@people2 = %IDForName;# 将hash中的值赋给数组


%IDForName2 = %IDForName; # 将一个hash中的值赋给另一个hash


$IDForName{'3'} = '王五'; # 增加
delete $IDForName{'3'}; # 删除
$name = $IDForName{'1'}; # 查找
$IDForName{'1'} = '赵六'; # 修改


@IDs = keys %IDForName; # 返回所有的 key
$IDAmount = keys %IDForName; # 返回 key 的数量


@names = values %IDForName; # 返回所有的 value
$nameAmount = values %IDForName; # 返回 value 的数量


%NameForID = reverse %IDForName; # 交换 key 和 value


# 判断是否存在某个键
if (exists $IDForName{'3'}) {
	print "this key already exists.\n";
}


# 迭代 hash
while(($id, $name) = each %IDForName) {
	print "$id => $name\n";
}


# 先对 key 按字符串排序排序后迭代 hash
foreach $id (sort keys %IDForName) {
	$name = $IDForName{$id};
	print "$id => $name\n";
}


# 先对 key 按数字排序排序后迭代 hash
foreach $id (sort{$a<=>$b} keys %IDForName) {
	$name = $IDForName{$id};
	print "$id => $name\n";
}


%ENV 是一个内置的 hash,我们可以通过它来得到系统的环境变量,如 PATH,$ENV{PATH}。

-- 更多参见:Perl 精萃

-- 声 明:转载请注明出处
-- Last Updated on 2012-06-29
-- Written by ShangBo on 2012-06-29
-- End



### C语言中的哈希数据结构 #### 定义哈希表节点 为了构建一个高效的哈希表,在C语言中通常定义两个主要结构体:一个是用于存储实际数据项的`DataNode`,另一个是指向这些节点并管理它们访问方式的桶(bucket)。这里先展示如何创建基本的数据节点。 ```c typedef struct _DataNode { uint32_t key; void* value; // 可以指向任何类型的值 struct _DataNode *next; // 链接到下一个具有相同hashcode的元素 } DataNode; ``` 此部分代码定义了一个名为`_DataNode`的结构体来表示哈希表内的单个条目[^1]。注意这里的`key`字段被设置为无符号整数类型(`uint32_t`),而`value`则是一个指针变量可以用来保存任意类型的数据对象;此外还包含了指向同一散列位置处其他项目的链接指针`next`。 #### 创建哈希函数 一个好的哈希算法对于确保哈希表性能至关重要。下面给出了一种简单的字符串到索引映射的方法作为例子: ```c unsigned int hash_function(const char* str, unsigned int table_size){ unsigned long hash = 5381; int c; while ((c = *str++)) hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ return hash % table_size; } ``` 这段程序实现了DJB2哈希算法的一个变体,它接收待处理的关键字串以及目标数组大小,并返回介于0至table_size-1之间的数值作为该键对应的槽位编号。 #### 初始化哈希表 接下来初始化哈希表本身,这涉及到分配适当数量的空间给各个桶,并将每个桶置为空列表形式准备接受新成员加入进来。 ```c #define INITIAL_SIZE 100 typedef struct HashTable{ DataNode **buckets; // 动态分配的一维指针数组 size_t capacity; // 表的最大容量 }s_HashTable; s_HashTable* create_hash_table(size_t initial_capacity){ s_HashTable *ht = malloc(sizeof(s_HashTable)); ht->capacity = initial_capacity ? : INITIAL_SIZE ; ht->buckets = calloc(ht->capacity , sizeof(DataNode *)); if (!ht || !ht->buckets ) { free(ht); return NULL; } return ht; } ``` 上述片段展示了怎样通过动态内存分配技术建立一个新的哈希表实例及其内部容器——即一系列预先设定长度的空闲链表头结点集合。 #### 插入操作 当要往已存在的哈希表里添加新的(key,value)对时,则需遵循如下逻辑流程执行插入动作: ```c int insert_into_hash_table(s_HashTable *ht, const char* key,void* val){ unsigned int index = hash_function((char*)key, ht->capacity); DataNode *new_node = (DataNode *)malloc(sizeof(DataNode)); new_node->key = *(uint32_t*)key; new_node->value=val; new_node->next=NULL; if(!ht->buckets[index]){ ht->buckets[index]=new_node; }else{ DataNode *current=ht->buckets[index]; while(current->next!=NULL){ current=current->next; } current->next=new_node; } return 0; } ``` 在此过程中,首先计算出指定关键字应当放置的位置index,之后检查对应位置是否已有记录存在。如果不存在就直接赋值;反之则遍历现有链条直至找到合适的地方追加进去。 #### 查找功能 最后提供一种方法去检索特定键关联起来的信息内容: ```c void* search_in_hash_table(s_HashTable *ht,const char* key){ unsigned int index = hash_function((char*)key, ht->capacity); DataNode *node = ht->buckets[index]; while(node != NULL && node->key !=*(uint32_t*)key ){ node=node->next; } if(node==NULL)return NULL;//未发现匹配项目 return node->value; } ``` 这个过程同样依赖之前提到过的哈希运算得出定位坐标,随后沿着可能形成的冲突路径逐一检验直到遇到相等条件为止或是到达终点仍未命中所需查找的目标。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值