侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

算法系列15天速成 第五天 五大经典查找【中】

技术  /  管理员 发布于 7年前   185

哈希查找:

    对的,他就是哈希查找,说到哈希,大家肯定要提到哈希函数,呵呵,这东西已经在我们脑子里面形成
固有思维了。大家一定要知道“哈希“中的对应关系。
     比如说: ”5“是一个要保存的数,然后我丢给哈希函数,哈希函数给我返回一个”2",那么此时的”5“
和“2”就建立一种对应关系,这种关系就是所谓的“哈希关系”,在实际应用中也就形成了”2“是key,”5“是value。
    那么有的朋友就会问如何做哈希,首先做哈希必须要遵守两点原则:
          ①:  key尽可能的分散,也就是我丢一个“6”和“5”给你,你都返回一个“2”,那么这样的哈希函数不尽完美。
          ②: 哈希函数尽可能的简单,也就是说丢一个“6”给你,你哈希函数要搞1小时才能给我,这样也是不好的。

其实常用的做哈希的手法有“五种”:
第一种:”直接定址法“。
                  很容易理解,key=Value+C; 这个“C"是常量。Value+C其实就是一个简单的哈希函数。
第二种:“除法取余法”。
                  很容易理解, key=value%C;解释同上。
第三种:“数字分析法”。
                  这种蛮有意思,比如有一组value1=112233,value2=112633,value3=119033,
                  针对这样的数我们分析数中间两个数比较波动,其他数不变。那么我们取key的值就可以是
                  key1=22,key2=26,key3=90。
第四种:“平方取中法”。此处忽略,见名识意。
第五种:“折叠法”。
                 这种蛮有意思,比如value=135790,要求key是2位数的散列值。那么我们将value变为13+57+90=160,
                 然后去掉高位“1”,此时key=60,哈哈,这就是他们的哈希关系,这样做的目的就是key与每一位value都相
                 关,来做到“散列地址”尽可能分散的目地。

正所谓常在河边走,哪有不湿鞋。哈希也一样,你哈希函数设计的再好,搞不好哪一次就撞楼了,那么抛给我们的问题
就是如果来解决“散列地址“的冲突。

其实解决冲突常用的手法也就2种:

第一种: “开放地址法“。
                 所谓”开放地址“,其实就是数组中未使用的地址。也就是说,在发生冲突的地方,后到的那个元素(可采用两种方式
                 :①线性探测,②函数探测)向数组后寻找"开放地址“然后把自己插进入。

第二种:”链接法“。
                这个大家暂时不懂也没关系,我就先介绍一下原理,就是在每个元素上放一个”指针域“,在发生冲突的地方,后到的那
               个元素将自己的数据域抛给冲突中的元素,此时冲突的地方就形成了一个链表。

上面铝四敲炊啵簿褪窍肴么蠹以凇鄙杓乒!昂汀苯饩龀逋弧罢饬礁龇矫嫣嵋坏悴慰己褪侄巍

那么下面就上代码了,
     设计函数采用:”除法取余法“。
     冲突方面采用:”开放地址线性探测法"。

复制代码 代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HashSearch
{
    class Program
    {
        //“除法取余法”
        static int hashLength = 13;

        //原数据
        static List<int> list = new List<int>() { 13, 29, 27, 28, 26, 30, 38 };

        //哈希表长度
        static int[] hash = new int[hashLength];

        static void Main(string[] args)
        {
            //创建hash
            for (int i = 0; i < list.Count; i++)
            {
                InsertHash(hash, hashLength, list[i]);
            }

            Console.WriteLine("Hash数据:" + string.Join(",", hash));

            while (true)
            {
                Console.WriteLine("\n请输入要查找数字:");
                int result = int.Parse(Console.ReadLine());
                var index = SearchHash(hash, hashLength, result);

                if (index != -1)
                    Console.WriteLine("数字" + result + "在索引的位置是:" + index);
                else
                    Console.WriteLine("呜呜," + result + " 在hash中没有找到!");

            }
        }

        ///<summary>
/// Hash表检索数据
///</summary>
///<param name="dic"></param>
///<param name="hashLength"></param>
///<param name="key"></param>
///<returns></returns>
        static int SearchHash(int[] hash, int hashLength, int key)
        {
            //哈希函数
            int hashAddress = key % hashLength;

            //指定hashAdrress对应值存在但不是关键值,则用开放寻址法解决
            while (hash[hashAddress] != 0 && hash[hashAddress] != key)
            {
                hashAddress = (++hashAddress) % hashLength;
            }

            //查找到了开放单元,表示查找失败
            if (hash[hashAddress] == 0)
                return -1;
            return hashAddress;

        }

        ///<summary>
///数据插入Hash表
///</summary>
///<param name="dic">哈希表</param>
///<param name="hashLength"></param>
///<param name="data"></param>
        static void InsertHash(int[] hash, int hashLength, int data)
        {
            //哈希函数
            int hashAddress = data % 13;

            //如果key存在,则说明已经被别人占用,此时必须解决冲突
            while (hash[hashAddress] != 0)
            {
                //用开放寻址法找到
                hashAddress = (++hashAddress) % hashLength;
            }

            //将data存入字典中
            hash[hashAddress] = data;
        }
    }
}

结果:

索引查找:
     一提到“索引”,估计大家第一反应就是“数据库索引”,对的,其实主键建立“索引”,就是方便我们在海量数据中查找。
关于“索引”的知识,估计大家都比我清楚,我就简单介绍下。
我们自己写算法来实现索引查找时常使用的三个术语:
第一:主表,      这个很简单,要查找的对象。
第二:索引项,   一般我们会用函数将一个主表划分成几个子表,每个子表建立一个索引,这个索引叫做索引项。
第三:索引表,    索引项的集合也就是索引表。

一般“索引项”包含三种内容:index,start,length

第一: index,也就是索引指向主表的关键字。
第二:start, 也就是index在主表中的位置。
第三:length, 也就是子表的区间长度。

复制代码 代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IndexSearchProgram
{
    class Program
    {
        ///<summary>
/// 索引项实体
///</summary>
        class IndexItem
        {
            //对应主表的值
            public int index;
            //主表记录区间段的开始位置
            public int start;
            //主表记录区间段的长度
            public int length;
        }

        static void Main(string[] args)
        {
            Console.WriteLine("原数据为:" + string.Join(",", students));


            int value = 205;

            Console.WriteLine("\n插入数据" + value);

            //将205插入集合中,过索引
            var index = insert(value);

            //如果插入成功,获取205元素所在的位置
            if (index == 1)
            {
                Console.WriteLine("\n插入后数据:" + string.Join(",", students));
                Console.WriteLine("\n数据元素:205在数组中的位置为 " + indexSearch(205) + "位");
            }

            Console.ReadLine();
        }

        ///<summary>
/// 学生主表
///</summary>
        static int[] students = {
                                   101,102,103,104,105,0,0,0,0,0,
                                   201,202,203,204,0,0,0,0,0,0,
                                   301,302,303,0,0,0,0,0,0,0
                                };
        ///<summary>
///学生索引表
///</summary>
        static IndexItem[] indexItem = {
                                  new IndexItem(){ index=1, start=0, length=5},
                                  new IndexItem(){ index=2, start=10, length=4},
                                  new IndexItem(){ index=3, start=20, length=3},
                                };

        ///<summary>
/// 查找数据
///</summary>
///<param name="key"></param>
///<returns></returns>
        public static int indexSearch(int key)
        {
            IndexItem item = null;

            // 建立索引规则
            var index = key / 100;

            //首先去索引找
            for (int i = 0; i < indexItem.Count(); i++)
            {
                if (indexItem[i].index == index)
                {
                    item = new IndexItem() { start = indexItem[i].start, length = indexItem[i].length };
                    break;
                }
            }

            //如果item为null,则说明在索引中查找失败
            if (item == null)
                return -1;

            for (int i = item.start; i < item.start + item.length; i++)
            {
                if (students[i] == key)
                {
                    return i;
                }
            }
            return -1;
        }

        ///<summary>
/// 插入数据
///</summary>
///<param name="key"></param>
///<returns></returns>
        public static int insert(int key)
        {
            IndexItem item = null;
            //建立索引规则
            var index = key / 100;
            int i = 0;
            for (i = 0; i < indexItem.Count(); i++)
            {
                //获取到了索引
                if (indexItem[i].index == index)
                {
                    item = new IndexItem()
                    {
                        start = indexItem[i].start,
                        length = indexItem[i].length
                    };
                    break;
                }
            }
            if (item == null)
                return -1;
            //更新主表
            students[item.start + item.length] = key;
            //更新索引表
            indexItem[i].length++;
            return 1;
        }
    }
}

结果:

ps: 哈希查找时间复杂度O(1)。

       索引查找时间复杂度:就拿上面的Demo来说是等于O(n/3)+O(length)


  • 上一条:
    算法系列15天速成 第六天 五大经典查找【下】
    下一条:
    算法系列15天速成 第四天 五大经典查找【上】
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 2024.07.09日OpenAI将终止对中国等国家和地区API服务(0个评论)
    • 2024/6/9最新免费公益节点SSR/V2ray/Shadowrocket/Clash节点分享|科学上网|免费梯子(0个评论)
    • 国外服务器实现api.openai.com反代nginx配置(0个评论)
    • 2024/4/28最新免费公益节点SSR/V2ray/Shadowrocket/Clash节点分享|科学上网|免费梯子(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-07
    • 2017-08
    • 2017-09
    • 2018-01
    • 2018-07
    • 2018-08
    • 2018-09
    • 2018-12
    • 2019-01
    • 2019-02
    • 2019-03
    • 2019-04
    • 2019-05
    • 2019-06
    • 2019-07
    • 2019-08
    • 2019-09
    • 2019-10
    • 2019-11
    • 2019-12
    • 2020-01
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2020-07
    • 2020-08
    • 2020-09
    • 2020-10
    • 2020-11
    • 2021-04
    • 2021-05
    • 2021-06
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-12
    • 2022-01
    • 2022-02
    • 2022-03
    • 2022-04
    • 2022-05
    • 2022-06
    • 2022-07
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-08
    • 2023-09
    • 2023-10
    • 2023-12
    • 2024-02
    • 2024-04
    • 2024-05
    • 2024-06
    • 2025-02
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客