Welcome to the website navigation,本站只接受合法正规的企业网站,欢迎站长们提交你的网站获得展示和流量有任何问题请联系站长,欢迎大家加入本站。

                
提交网站
  • 网站:76083
  • 待审:5
  • APP:577
  • 文章:304411
  • 会员:56004
文字内链包年1000元 文字内链包年1000元 文字内链包年1000元 AI办公网站 AI绘画工具 AIchat

名站导航为爱好php程序的朋友们提供php相关的教程知识。

PhP程序中使用最为频繁的数据类型非字符串和数组莫属,PhP程序比较容易上手也得益于非常灵活的数组类型。 在开始详细介绍这些数据类型之前有必要介绍一下哈希表(hashTable)。 哈希表是PhP程序实现中尤为关键的数据结构。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

哈希表在实践中使用的非常广泛,例如编译器通常会维护的一个符号表来保存标记,很多高级语言中也显式的支持哈希表。 哈希表通常提供查找(Search),插入(Insert),删除(Delete)等操作,这些操作在最坏的情况下和链表的性能一样为O(n)。 不过通常并不会这么坏,合理设计的哈希算法能有效的避免这类情况,通常哈希表的这些操作时间复杂度为O(1)。 这也是它被钟爱的原因。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

正是因为哈希表在使用上的便利性及效率上的表现,目前大部分动态语言的实现中都使用了哈希表。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

为了方便读者阅读后面的内容,这里提前列举一下hashTable实现中出现的基本概念。 哈希表是一种通过哈希函数,将特定的键映射到特定值的一种数据结构,它维护键和值之间一一对应关系。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

键(key):用于操作数据的标示,例如PhP程序数组中的索引,或者字符串键等等。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

槽(slot/bucket):哈希表中用于保存数据的一个单元,也就是数据真正存放的容器。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

哈希函数(hash function):将key映射(map)到数据应该存放的slot所在位置的函数。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

哈希冲突(hash collision):哈希函数将两个不同的key映射到同一个索引的情况。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

哈希表可以理解为数组的扩展或者关联数组,数组使用数字下标来寻址,如果关键字(key)的范围较小且是数字的话, 我们可以直接使用数组来完成哈希表,而如果关键字范围太大,如果直接使用数组我们需要为所有可能的key申请空间。 很多情况下这是不现实的。即使空间足够,空间利用率也会很低,这并不理想。同时键也可能并不是数字, 在PhP程序中尤为如此,所以人们使用一种映射函数(哈希函数)来将key映射到特定的域中:631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

h(key) -> index631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

通过合理设计的哈希函数,我们就能将key映射到合适的范围,因为我们的key空间可以很大(例如字符串key), 在映射到一个较小的空间中时可能会出现两个不同的key映射被到同一个index上的情况, 这就是我们所说的出现了冲突。 目前解决hash冲突的方法主要有两种:链接法和开放寻址法。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

冲突解决631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

链接法:链接法通过使用一个链表来保存slot值的方式来解决冲突,也就是当不同的key映射到一个槽中的时候使用链表来保存这些值。 所以使用链接法是在最坏的情况下,也就是所有的key都映射到同一个槽中了,操作链表的时间复杂度为O(n)。 所以选择一个合适的哈希函数是最为关键的。目前PhP程序中hashTable的实现就是采用这种方式来解决冲突的。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

开放寻址法:通常还有另外一种解决冲突的方法:开放寻址法。使用开放寻址法是槽本身直接存放数据, 在插入数据时如果key所映射到的索引已经有数据了,这说明发生了冲突,这是会寻找下一个槽, 如果该槽也被占用了则继续寻找下一个槽,直到寻找到没有被占用的槽,在查找时也使用同样的策律来进行。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

哈希表的实现631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

在了解到哈希表的原理之后要实现一个哈希表也很容易,主要需要完成的工作只有三点:631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

实现哈希函数631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

冲突的解决631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

操作接口的实现631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

首先我们需要一个容器来保存我们的哈希表,哈希表需要保存的内容主要是保存进来的的数据, 同时为了方便的得知哈希表中存储的元素个数,需要保存一个大小字段, 第二个需要的就是保存数据的容器了。作为具体实例操作,下面将实现一个简易的哈希表。基本的数据结构主要有两个, 一个用于保存哈希表本身,另外一个就是用于实际保存数据的单链表了,定义如下:631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

typedef struct _Bucket631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

{631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    char *key;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    void *value;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    struct _Bucket *next;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

} Bucket;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

typedef struct _hashTable631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

{631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    int size;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    Bucket* buckets;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

} hashTable;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

上面的定义和PhP程序中的实现类似,为了便于理解裁剪了大部分无关的细节,在本节中为了简化, key的数据类型为字符串,而存储的数据类型可以为任意类型。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

Bucket结构体是一个单链表,这是为了解决多个key哈希冲突的问题,也就是前面所提到的的链接法。 当多个key映射到同一个index的时候将冲突的元素链接起来。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

哈希函数需要尽可能的将不同的key映射到不同的槽(slot或者bucket)中,首先我们采用一种最为简单的哈希算法实现: 将key字符串的所有字符加起来,然后以结果对哈希表的大小取模,这样索引就能落在数组索引的范围之内了。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

static int hash_str(char *key)631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

{631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    int hash = 0;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    char *cur = key;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    while(*(cur ) != '\0') {631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

        hash = *cur;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    }631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    return hash;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

}631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

// 使用这个宏来求得key在哈希表中的索引631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

#define hASh_INDEX(ht, key) (hash_str((key)) % (ht)->size)631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

这个哈希算法比较简单,它的效果并不好,在实际场景下不会使用这种哈希算法, 例如PhP程序中使用的是称为DJBX33A算法, 这里列举了Mysql,OpenSSL等开源软件使用的哈希算法, 有兴趣的读者可以前往参考。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

操作接口的实现631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

为了操作哈希表,实现了如下几个操作函数:631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

int hash_init(hashTable *ht);                               // 初始化哈希表631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

int hash_lookup(hashTable *ht, char *key, void **result);   // 根据key查找内容631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

int hash_insert(hashTable *ht, char *key, void *value);     // 将内容插入到哈希表中631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

int hash_remove(hashTable *ht, char *key);                  // 删除key所指向的内容631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

int hash_destroy(hashTable *ht);631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

下面以插入和获取操作函数为例:631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

int hash_insert(hashTable *ht, char *key, void *value)631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

{631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    // check if we need to resize the hashtable631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    resize_hash_table_if_needed(ht);    // 哈希表不固定大小,当插入的内容快占满哈表的存储空间631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

                                        // 将对哈希表进行扩容, 以便容纳所有的元素631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    int index = hASh_INDEX(ht, key);    // 找到key所映射到的索引631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    Bucket *org_bucket = ht->buckets[index];631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    Bucket *bucket = (Bucket *)malloc(sizeof(Bucket)); // 为新元素申请空间631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    bucket->key   = strdup(key);631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    // 将值内容保存进来, 这里只是简单的将指针指向要存储的内容,而没有将内容复制。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    bucket->value = value;  631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    LOG_MSG("Insert data p: %p\n", value);631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    ht->elem_num = 1; // 记录一下现在哈希表中的元素个数631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    if(org_bucket != NULL) { // 发生了碰撞,将新元素放置在链表的头部631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

        LOG_MSG("Index collision found with org hashtable: %p\n", org_bucket);631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

        bucket->next = org_bucket;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    }631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    ht->buckets[index]= bucket;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    LOG_MSG("Element inserted at index %i, now we have: %i elements\n",631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

        index, ht->elem_num);631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    return SUCCESS;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

}631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

上面这个哈希表的插入操作比较简单,简单的以key做哈希,找到元素应该存储的位置,并检查该位置是否已经有了内容, 如果发生碰撞则将新元素链接到原有元素链表头部。在查找时也按照同样的策略,找到元素所在的位置,如果存在元素, 则将该链表的所有元素的key和要查找的key依次对比, 直到找到一致的元素,否则说明该值没有匹配的内容。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

int hash_lookup(hashTable *ht, char *key, void **result)631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

{631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    int index = hASh_INDEX(ht, key);631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    Bucket *bucket = ht->buckets[index];631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    if(bucket == NULL) return FAILED;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    // 查找这个链表以便找到正确的元素,通常这个链表应该是只有一个元素的,也就不用多次631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    // 循环。要保证这一点需要有一个合适的哈希算法,见前面相关哈希函数的链接。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    while(bucket)631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    {631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

        if(strcmp(bucket->key, key) == 0)631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

        {631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

            LOG_MSG("hashTable found key in index: %i with  key: %s value: %p\n",631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

                index, key, bucket->value);631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

            *result = bucket->value;    631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

            return SUCCESS;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

        }631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

        bucket = bucket->next;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    }631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

 631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    LOG_MSG("hashTable lookup missed the key: %s\n", key);631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

    return FAILED;631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

}631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

PhP程序中数组是基于哈希表实现的,依次给数组添加元素时,元素之间是有先后顺序的,而这里的哈希表在物理位置上显然是接近平均分布的, 这样是无法根据插入的先后顺序获取到这些元素的,在PhP程序的实现中Bucket结构体还维护了另一个指针字段来维护元素之间的关系。 具体内容在后一小节PhP程序中的hashTable中进行详细说明。上面的例子就是PhP程序中实现的一个精简版。631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!


631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

名站网址导航

PhP程序内核探索:理解Zend里的哈希表631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

631AIChat_企业网址导航_网址分类目录_企业黄页网址提交查询专业网站!

好了关于php程序的知识就说到这里希望可以帮助需要的朋友。,

标签:

分享到:

  admin

注册时间:

网站:0 个   APP:3 个  文章:0 篇

  • 76083

    网站

  • 577

    APP

  • 304411

    文章

  • 56004

    会员

赶快注册账号,推广您的网站吧!
文章分类
热门网站
最新入驻APP小程序

宝贝市场2023-02-08

宝贝市场——买手和卖家商品展示

夺宝助手2023-02-08

夺宝助手小程序,查看每日快夺宝平

查诚信2023-02-08

查诚信是一款免费的商业查询工具

车价天天报2023-02-08

快速连接汽车销售,获知汽车最新报

考勤助理小程序2023-02-08

上班签到考勤,实时定位,后台轻松

汽车报价大全查询2023-02-08

汽车报价大全查询提供最新汽车市