大数据之什么是Hash表

简介:   大数据之什么是Hash表,Hash,一般翻译做“散列”,也有直接音译为“哈希”的,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法。顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙。

  大数据之什么是Hash表,Hash,一般翻译做“散列”,也有直接音译为“哈希”的,它是基于快速存取的角度设计的,也是一种典型的“空间换时间”的做法。顾名思义,该数据结构可以理解为一个线性表,但是其中的元素不是紧密排列的,而是可能存在空隙。

​ 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。比如我们存储70个元素,但我们可能为这70个元素申请了100个元素的空间。70/100=0.7,这个数字称为负载(加载)因子。我们之所以这样做,也 是为了“快速存取”的目的。我们基于一种结果尽可能随机平均分布的固定函数H为每个元素安排存储位置,以达到快速存取。但是由于此随机性,也必然导致一个问题就是冲突。所谓冲突,即两个元素通过散列函数H得到的地址相同,那么这两个元素称为“同义词”。这类似于70个人去一个有100个椅子的饭店吃饭。散列函数的计算结果是一个存储单位地址,每个存储单位称为“桶”。设一个散列表有m个桶,则散列函数的值域应为[0,m-1]。

  这些元素是按照什么样的规则存储到数组中呢。一般情况是通过hash(key)%len获得,也就是元素的key的哈希值对数组长度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存储在数组下标为12的位置

2.hash表扩容的理解

可是当哈希表接近装满时,因为数组的扩容问题,性能较低(转移到更大的哈希表中).

Java默认的散列单元大小全部都是2的幂,初始值为16(2的4次幂)。假如16条链表中的75%链接有数据的时候,则认为加载因子达到默认的0.75。HahSet开始重新散列,也就是将原来的散列结构全部抛弃,重新开辟一个散列单元大小为32(2的5次幂)的散列结果,并重新计算各个数据的存储位置。以此类推下去.....

负载(加载)因子:0.75.-->hash表提供的空间是16 也就是说当到达12的时候就扩容

3.排重机制的实现

假如我们有一个数据(散列码76268),而此时的HashSet有128个散列单元,那么这个数据将有可能插入到数组的第108个链表中(76268%128=108)。但这只是有可能,如果在第108号链表中发现有一个老数据与新数据equals()=true的话,这个新数据将被视为已经加入,而不再重复丢入链表。

4.优点

哈希表的插入和查找是很优秀的.

对于查找:直接根据数据的散列码和散列表的数组大小计算除余后,就得到了所在数组的位置,然后再查找链表中是否有这个数据即可。因为数组本身查找速度快,所以查找的效率高低体现在链表中,但是真实情况下在一条链表中的数据又很少,有的甚至没有,所以几乎没有什么迭代的代价。所以散列表的查找效率建立在散列单元所指向的链表中数据的多少上.

对于插入:数组的插入速度慢,而链表的插入速度快.当我们使用哈希表时,不需要更改数组的结构,只需要在找到对应的数组下标后,进入对应的链表,操作链表即可.所以hash表的整体插入速度也很快.

5.模拟实现代码

Node类

public class Node {
// key、value模拟键值对的数据
    public Integer key;
    public String value;
    // 下一节点的引用
    public Node next;
    public Node() {
    }
    public Node(int key, String value) {
        this.key = key;
        this.value = value;
    }
 
}

MyLinkedList类

    public class MyLinkedList {
    // 根节点
    private Node root;
 
    public MyLinkedList() {
        root = new Node();
    }
    /**
     * 添加数据,key值必须唯一,如果重复值将被覆盖
     * @param key
     */
    public void add(int key, String value) {
 
        Node newNode = new Node(key, value);
        Node current = root;
        while (current.next != null) {
            if(current.next.key == key) {
                current.next.value = value;
                return;
            }
            current = current.next;
        }
        current.next = newNode;
    }
 
    /**
     * 删除数据
     * @param key
     * @return
     */
    public boolean delete(int key) {
 
        Node current = root;
        while (current.next != null) {
            if(current.next.key == key) {
                current.next = current.next.next;
                return true;
            }
            current = current.next;
        }
        return false;
    }
 
    /**
     * 根据key获取value
     * @param key
     * @return
     */
    public String get(int key) {
 
        Node current = root;
        while (current.next != null) {
            if(current.next.key == key) {
                return current.next.value;
            }
            current = current.next;
        }
        return null;
    }
 
    /**
     * 遍历链表,列出所有数据
     * @return
     */
    public String list() {
 
        String str = "";
        Node current = root.next;
        while (current != null) {
            str += "(" + current.key + "," + current.value + "),";
            current = current.next;
        }
        return str;
    }
 
    @Override
    public String toString() {
        return list();
    }
}

MyHashMap类

// 哈希表
public class MyHashMap {
 
    // 链表数组,数组的每一项都是一个链表
    private MyLinkedList[] arr;
    // 数组的大小
    private int maxSize;
 
    /**
     * 空参构造,默认数组大小为10
     */
    public MyHashMap() {
        maxSize = 10;
        arr = new MyLinkedList[maxSize];
    }
 
    /**
     * 带参构造,数组大小自定义
     * @param maxSize
     */
    public MyHashMap(int maxSize) {
        this.maxSize = maxSize;
        arr = new MyLinkedList[maxSize];
    }
 
    /**
     * 添加数据,key值必须唯一
     * @param key
     * @param value
     */
    public void put(int key, String value) {
 
        int index = getHashIndex(key);
        if(arr[index] == null) {
            arr[index] = new MyLinkedList();
        }
        arr[index].add(key, value);
    }
 
    /**
     * 删除数据
     * @param key
     * @return
     */
    public boolean delete(int key) {
 
        int index = getHashIndex(key);
        if(arr[index] != null) {
            return arr[index].delete(key);
        }
        return false;
    }
 
    /**
     * 根据key获取value
     * @param key
     * @return
     */
    public String get(int key) {
 
        int index = getHashIndex(key);
        if(arr[index] != null) {
            return arr[index].get(key);
        }
        return null;
    }
 
    /**
     * 获取数组下标
     * @param key
     * @return
     */
    private int getHashIndex(Integer key) {
        return key.hashCode() % maxSize;
    }
 
    /**
     * 遍历数组中所有链表的数据
     * @return
     */
    public String list() {
 
        String str = "[ ";
        for (int i = 0; i < maxSize; i++) {
            if(arr[i] != null) {
                str += arr[i].toString();
            }
        }
        str = str.substring(0, str.length()-1);
        str += " ]";
        return str;
    }
 
    @Override
    public String toString() {
        return list();
    }
}

测试类

public class Test {
 
    public static void main(String[] args) {
 
        MyHashMap map = new MyHashMap(20);
 
        map.put(5, "aaa");
        map.put(8, "bbb");
        map.put(3, "ccc");
        map.put(8, "bbb");
        map.put(2, "ddd");
        map.put(9, "eee");
 
        System.out.println(map);
        System.out.println(map.get(3));
        System.out.println(map.delete(2));
        System.out.println(map);
    }
}
相关实践学习
简单用户画像分析
本场景主要介绍基于海量日志数据进行简单用户画像分析为背景,如何通过使用DataWorks完成数据采集 、加工数据、配置数据质量监控和数据可视化展现等任务。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
相关文章
|
6月前
|
存储 SQL 数据采集
一篇文章彻底理解大数据的列式存储
一篇文章彻底理解大数据的列式存储
一篇文章彻底理解大数据的列式存储
|
3天前
|
数据采集 编解码 搜索推荐
大数据中的移动数据
【4月更文挑战第11天】移动数据,主要来自智能手机等设备,包括位置、行为、设备信息和网络状态等方面,用于理解用户习惯、优化服务和提升业务效率。位置数据揭示用户移动模式,行为数据帮助构建用户画像,设备信息助力应用优化,网络状态数据则影响体验和成本。尽管移动数据分析广泛应用,但需关注数据隐私、安全和质量,遵守法规并确保数据处理的合法性与安全性。
8 2
|
Java 大数据 索引
大数据基础之JAVA数组
大数据基础之JAVA数组
85 0
|
存储 数据采集 分布式计算
大数据热是华而不实吗?大数据和小数据有什么本质区别
大数据热是华而不实吗?大数据和小数据有什么本质区别
大数据热是华而不实吗?大数据和小数据有什么本质区别
|
监控 大数据 定位技术
大数据概念
大数据相关概念
|
存储 数据可视化 算法
一、大数据概念
一、大数据概念
220 0
|
存储 数据采集 分布式计算
大数据,数据从哪里来?
0、题记 之前自己也做过一个大数据方面的讲座,讲解大数据背景、大数据原理、Hadoop(MapReduce、HDFS、分布式)、NoSql非关系型数据库存储、大数据应用(微博来源追踪、微信jiankong等)。诚然,大型互联网公司早已很早布局云计算、使用大数据。 而中、小企业在大数据的浪潮下,也想分得一碗羹,这就遇到棘手的源头问题:大数据,数据从哪里来?
110 0
|
存储 大数据 索引
大数据:大数据之数组
好程序员:大数据培训分享实用大数据之数组1.5.1 数组的定义与元素访问 数组是一个容器, 是一个用来存储指定数据类型的容器注意事项: 数组是一个定长的容器, 一旦实例化完成, 长度不能修改名词解释: 数组长度: 指的就是这个容器的容量, 表示这个数组中能存储多少个数据 元素: 指的就是数组中.
662 0