浅入Hash算法、及用 PHP 代码实现Hash表

Hash表

俗称散列表、是比较重要的数据结构,它是把关键字通过某个实现函数(Hash函数)映射到数组(Hash 表)中的某一个特定位置,以加快查找的速度。

Hash函数

  它的作用是将任意的Key通过指定的算法换算成固定的长度的值(Hash值)、但是在某些情况下不同的Key通过Hash函数转换过后可能会产生相同的值,这种现象称之为Hash碰撞.

Hash算法

  • 直接取余法
Hash表的大小为L、指定Key是K、则:换算的值 L(K) = fmod(K, L); 
  • 乘积取余法
关健字             K
常数C在(0, 1)区间  C
Hash表大小         L

L(k) = floor(L *fmod(KC, 1))

如果 K是字符串 把字符串里每一个字符 ord()后累加。

  • Timess33算法

这里可以参考下大V的Blog ===
鸟哥Blog

PHP实现Hash表

图示

流程图

代码

//hash表
class HashTable
{
    private $buckets;
    private $size = 10;

    public function __construct()
    {
        //创建一个长度为10的一个数组
        $this->buckets = new \SplFixedArray($this->size);
    }

    /**
     * 通过此简单函数转换成指定映射成一个指定位置
     *
     * @param string $key
     * @return float
     */
    public function buildHashValByKey(string $key)
    {
        $hashVal = 0;
        $len     = strlen($key);

        for ($i = 0; $i < $len; $i++) {
            $hashVal += ord($key[$i]);
        }

        return fmod($hashVal, $this->size);
    }

    /**
     * 插入 key val
     *
     * @param string $key
     * @param $val
     */
    public function insert(string $key, $val)
    {
        $index = $this->buildHashValByKey($key);

        if (isset($this->bukets[$index])) {
            //为了解决 Hash 冲突,这里采用常用的 拉链法
            //如果有值 采用链表的头插法插入新数据
            $newHashNode = new HashNode($key, $val, $this->buckets[$index]);
        } else {
            $newHashNode = new HashNode($key, $val, null);
        }

        $this->buckets[$index] = $newHashNode;
    }

    /**
     * 通过指定 Key 查询 值
     *
     * @param string $key
     * @return mixed|null
     */
    public function find(string $key)
    {
        $index = $this->buildHashValByKey($key);

        /** @var HashNode $node */
        $node  = $this->getNodeByIndex($index);

        if (!$node) {
            return null;
        }

        while ($node) {
            if ($node->getKey() == $key) {
                return $node->getVal();
            }
            //断续寻找下一个结点
            $node = $node->getNextNode();
        }

        return null;
    }
    
    /**
     * 直接获取节点
     *
     * @param float $index
     * @return |null
     */
    public function getNodeByIndex(float $index)
    {
        return $this->buckets[$index] ?? null;
    }

}

//链表节点
class HashNode
{
    private $key;
    private $val;
    private $nextNode;

    public function __construct($key, $val, HashNode $nextNode = null)
    {
        $this->key = $key;
        $this->val = $val;
        $this->nextNode = $nextNode;
    }

    /**
     * @return mixed
     */
    public function getKey()
    {
        return $this->key;
    }

    /**
     * @return mixed
     */
    public function getVal()
    {
        return $this->val;
    }

    /**
     * @return mixed
     */
    public function getNextNode()
    {
        return $this->nextNode;
    }
}


测试

<?php

namespace Tests;

class HashTableTest extends TestCase
{

    /**
     * @test
     */
    public function testTable()
    {
         $table = new HashTable();

        $table->insert('key1', 'value1');
        $this->assertEquals(8, $table->buildHashValByKey('key1'));
        $this->assertEquals('value1', $table->find('key1'));

        $table->insert('key12', 'value12');
        $this->assertEquals(8, $table->buildHashValByKey('key12'));
        $this->assertEquals('value12', $table->find('key12'));

        //Hash碰撞后采用的拉链法存储
        $this->assertEquals('key1', $table->getNodeByIndex(8)->getNextNode()->getKey());


        $table->insert('key13', 'value13');
        $this->assertEquals(9, $table->buildHashValByKey('key13'));
        $this->assertEquals('value13', $table->find('key13'));
    }
}


谢谢~~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容