编程进阶网编程进阶网
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 01.Hash算法待完善

目录介绍

  • 01.线性探测
  • 02.代码案例
  • 03.测试代码

好消息

  • 博客笔记大汇总【15年10月到至今】,包括Java基础及深入知识点,Android技术博客,Python学习笔记等等,还包括平时开发中遇到的bug汇总,当然也在工作之余收集了大量的面试题,长期更新维护并且修正,持续完善……开源的文件是markdown格式的!同时也开源了生活博客,从12年起,积累共计N篇[近100万字,陆续搬到网上],转载请注明出处,谢谢!所有博客陆续更新到GitHub上!
  • 链接地址:https://github.com/yangchong211/YCBlogs
  • 如果觉得好,可以star一下,谢谢!当然也欢迎提出建议,万事起于忽微,量变引起质变!

01.线性探测

  • 在线性探测中,它会线性的查找空白单元。比如如果 5421 是要插入数据的位置,但是它已经被占用了,那么就使用5422,如果5422也被占用了,那么使用5423,以此类推,数组下标依次递增,直到找到空白的位置。这就叫做线性探测,因为它沿着数组下标一步一步顺序的查找空白单元。

02.代码案例

  • 代码如下所示
    public class MyHashTable {
        private DataItem[] hashArray;   //DataItem类,表示每个数据项信息
        private int arraySize;//数组的初始大小
        private int itemNum;//数组实际存储了多少项数据
        private DataItem nonItem;//用于删除数据项
         
        public MyHashTable(int arraySize){
            this.arraySize = arraySize;
            hashArray = new DataItem[arraySize];
            nonItem = new DataItem(-1);//删除的数据项下标为-1
        }
        //判断数组是否存储满了
        public boolean isFull(){
            return (itemNum == arraySize);
        }
         
        //判断数组是否为空
        public boolean isEmpty(){
            return (itemNum == 0);
        }
         
        //打印数组内容
        public void display(){
            System.out.println("Table:");
            for(int j = 0 ; j < arraySize ; j++){
                if(hashArray[j] != null){
                    System.out.print(hashArray[j].getKey() + " ");
                }else{
                    System.out.print("** ");
                }
            }
        }
        //通过哈希函数转换得到数组下标
        public int hashFunction(int key){
            return key%arraySize;
        }
         
        //插入数据项
        public void insert(DataItem item){
            if(isFull()){
                //扩展哈希表
                System.out.println("哈希表已满,重新哈希化...");
                extendHashTable();
            }
            int key = item.getKey();
            int hashVal = hashFunction(key);
            while(hashArray[hashVal] != null && hashArray[hashVal].getKey() != -1){
                ++hashVal;
                hashVal %= arraySize;
            }
            hashArray[hashVal] = item;
            itemNum++;
        }
        /**
         * 数组有固定的大小,而且不能扩展,所以扩展哈希表只能另外创建一个更大的数组,然后把旧数组中的数据插到新的数组中。
         * 但是哈希表是根据数组大小计算给定数据的位置的,所以这些数据项不能再放在新数组中和老数组相同的位置上。
         * 因此不能直接拷贝,需要按顺序遍历老数组,并使用insert方法向新数组中插入每个数据项。
         * 这个过程叫做重新哈希化。这是一个耗时的过程,但如果数组要进行扩展,这个过程是必须的。
         */
        public void extendHashTable(){
            int num = arraySize;
            itemNum = 0;//重新计数,因为下面要把原来的数据转移到新的扩张的数组中
            arraySize *= 2;//数组大小翻倍
            DataItem[] oldHashArray = hashArray;
            hashArray = new DataItem[arraySize];
            for(int i = 0 ; i < num ; i++){
                insert(oldHashArray[i]);
            }
        }
         
        //删除数据项
        public DataItem delete(int key){
            if(isEmpty()){
                System.out.println("Hash Table is Empty!");
                return null;
            }
            int hashVal = hashFunction(key);
            while(hashArray[hashVal] != null){
                if(hashArray[hashVal].getKey() == key){
                    DataItem temp = hashArray[hashVal];
                    hashArray[hashVal] = nonItem;//nonItem表示空Item,其key为-1
                    itemNum--;
                    return temp;
                }
                ++hashVal;
                hashVal %= arraySize;
            }
            return null;
        }
         
        //查找数据项
        public DataItem find(int key){
            int hashVal = hashFunction(key);
            while(hashArray[hashVal] != null){
                if(hashArray[hashVal].getKey() == key){
                    return hashArray[hashVal];
                }
                ++hashVal;
                hashVal %= arraySize;
            }
            return null;
        }
         
        public static class DataItem{
            private int iData;
            public DataItem(int iData){
                this.iData = iData;
            }
            public int getKey(){
                return iData;
            }
        }
    }
  • 需要注意:
    • 当哈希表变得太满时,我们需要扩展数组,但是需要注意的是,数据项不能放到新数组中和老数组相同的位置,而是要根据数组大小重新计算插入位置。这是一个比较耗时的过程,所以一般我们要确定数据的范围,给定好数组的大小,而不再扩容。
    • 另外,当哈希表变得比较满时,我们每插入一个新的数据,都要频繁的探测插入位置,因为可能很多位置都被前面插入的数据所占用了,这称为聚集。数组填的越满,聚集越可能发生。

参考文献

  • 极客时间,王争大神,数据结构和算法之美

01.关于博客汇总链接

  • 1.技术博客汇总
  • 2.开源项目汇总
  • 3.生活博客汇总
  • 4.喜马拉雅音频汇总
  • 5.其他汇总

02.关于我的博客

  • github:https://github.com/yangchong211
  • 知乎:https://www.zhihu.com/people/yczbj/activities
  • 简书:http://www.jianshu.com/u/b7b2c6ed9284
  • csdn:http://my.csdn.net/m0_37700275
  • 喜马拉雅听书:http://www.ximalaya.com/zhubo/71989305/
  • 开源中国:https://my.oschina.net/zbj1618/blog
  • 泡在网上的日子:http://www.jcodecraeer.com/member/content_list.php?channelid=1
  • 邮箱:yangchong211@163.com
  • 阿里云博客:https://yq.aliyun.com/users/article?spm=5176.100- 239.headeruserinfo.3.dT4bcV
  • segmentfault头条:https://segmentfault.com/u/xiangjianyu/articles
  • 掘金:https://juejin.im/user/5939433efe88c2006afa0c6e
贡献者: yangchong211