前言:

HashSet是一种数据结构为基本操作(add, remove, contains and size)提供恒定的时间性能,假设哈希函数在桶之间正确地分散元素。有许多方法可以实现这种数据结构。这篇文章主要使用链表+数组在Java中简单实现hashmap。

1.定义一个表示链表节点的类

class Node<T> {T data;Node next;Node(T data) {this.data = data;this.next = null;}@Overridepublic String toString() {return "(" + this.data + ")";}}复制代码

2.插入元素

插入元素,键和值将执行以下操作:

  1. 首先计算元素的哈希码,通常是一个int。两个不同的对象可以具有相同的哈希码,因为可能存在无限数量的元素和有限数量的整数。
  2. 然后使用模数作为hashCode (key) % array_length使用哈希码计算数组中的索引。这里两个不同的哈希码可以映射到相同的索引。
  3. 获取上面计算的此索引的链接列表将元素存储在此索引中。由于冲突,使用链表非常重要:可以使用具有相同哈希码的两个不同键或映射到同一索引的两个不同哈希码。

插入实现计算size():

public class MyHashSet<T> {private static final Integer INITIAL_CAPACITY = 1 << 4; // 16private Node<T>[] buckets;private int size;public MyHashSet(final int capacity) {this.buckets = new Node[capacity];this.size = 0;}public MyHashSet() {this(INITIAL_CAPACITY);}public void add(T t) {int index = hashCode(t) % buckets.length;Node bucket = buckets[index];Node<T> newNode = new Node<>(t);if (bucket == null) {buckets[index] = newNode;size++;return;}while (bucket.next != null) {if (bucket.data.equals(t)) {return;}bucket = bucket.next;}// 仅在最后一个元素没有添加值时才添加if (!bucket.data.equals(t)) {bucket.next = newNode;size++;}}public int size() {return size;}@Overridepublic String toString() {final StringBuilder sb = new StringBuilder("[");for (Node node: buckets) {while (node != null) {sb.append(node);node = node.next;}}sb.append("]");return sb.toString();}private int hashCode(T t) {return t == null ? 0 : t.hashCode();}}复制代码

3.删除元素

使用以下步骤从hashSet中删除元素:

  1. 计算元素中的哈希码,然后使用模运算从哈希码计算索引。
  2. 获取上面计算的索引的链接列表,并在链接列表中搜索具有此值的值。
  3. 通过更改上一个元素的下一个引用来删除节点。
public T remove(T t) {int index = hashCode(t) % buckets.length;Node bucket = buckets[index];if (bucket == null) {throw new NoSuchElementException("No Element Found"); //匹配不上}if (bucket.data.equals(t)) {buckets[index] = bucket.next;size--;return t;}Node prev = bucket;while (bucket != null) {if (bucket.data.equals(t)) {prev.next = bucket.next;size--;return t;}prev = bucket;bucket = bucket.next;}return null;
}复制代码

4.测试

@Test
public void testMyHashSet() {MyHashSet<Integer> set = new MyHashSet<>();set.add(3);set.add(4);set.add(8);set.add(4);set.add(8);set.add(1000);assertEquals(4, set.size()); assertEquals(Integer.valueOf(8), set.remove(8));assertEquals(3, set.size());
}@Testpublic void testMyHashSet1() {MyHashSet<String> set = new MyHashSet<>();set.add("USA");set.add("Nepal");set.add("England");set.add("Netherland");set.add("Canada");set.add("Bhutan");assertEquals(6, set.size());// test removal of elementassertEquals("Bhutan", set.remove("Bhutan"));assertEquals(5, set.size());}复制代码

5.总结

1. 时间复杂

将不同的Keys映射到同一索引可能会发生冲突。如果冲突的数量非常高,最坏情况的运行时间为O(N),其中N是Keys的数量。但是我们通常假设一个良好的实现,将冲突保持在最小,查找时间为O(1)。

2.以上就是关于如何使用基于数组的链表实现hashSet.

转载于:https://juejin.im/post/5cf72c3ef265da1b6b1cc417

Java 自定义HashSet相关推荐

  1. Java集合 -- HashSet 和 HashMap

    HashSet 集合 HashMap 集合 HashSet集合 1.1 Set 接口的特点 Set体系的集合: A:存入集合的顺序和取出集合的顺序不一致 B:没有索引 C:存入集合的元素没有重复 1. ...

  2. Java基础-TreeSet与Java自定义类型的排序

    TreeSet与Java自定义类型的排序 演示TreeSet对String是可排序的 TreeSet无法对自定义类型进行排序 比较规则怎么写 自平衡二叉树结构 实现比较器接口 Collections工 ...

  3. Java集合 HashSet 和 HashMap

    HashSet 集合 HashMap 集合 HashSet集合 Set 接口的特点 Set体系的集合: 存入集合的顺序和取出集合的顺序不一致 没有索引 存入集合的元素没有重复 HashSet 使用&a ...

  4. 新手小白学JAVA Set HashSet Map HashMap

    1 Map接口 1.1 概述 Java.util接口Map<K,V> 类型参数 : K - 表示此映射所维护的键 V – 表示此映射所维护的对应的值 也叫做哈希表.散列表. 常用于键值对结 ...

  5. java自定义校验注解

    前言 在日常的开发中可能会对手机号.邮箱.身份证号的合法性进行校验,然而每次使用if语句调用校验函数进行校验又显得过于麻烦,这时候自定义校验注解用处就很大了.此文编写一个对应0,1值的校验. 1.引入 ...

  6. Java 自定义排序

    文章目录 数组排序 包装类排序 Java 自定义排序 1.实现 Comparable 接口并重写 compareTo() 方法 2.实现 Comparator 接口,重写 compare() 方法. ...

  7. 数据脱敏——基于Java自定义注解实现日志字段脱敏

    上文说了数据过敏主要有两个思路:第一个就是在序列化实体之前先把需要脱敏的字段进行处理,之后正常序列化:第二个就是在实体序列化的时候,对要脱敏的字段进行处理. 脱敏实现思路 这里探讨第一种方法,用基于自 ...

  8. Java 自定义线程池

    Java 自定义线程池 https://www.cnblogs.com/yaoxiaowen/p/6576898.html public ThreadPoolExecutor(int corePool ...

  9. java 自定义注解_两步实现Java自定义注解

    什么是注解? 注解就是为容器提供元数据,例如@Controller 注解则是标记了该Bean需要交给Spring容器进行管理. 那么我们怎么去实现自个的注解,也就是自定义注解呢? 一.自定义一个注解( ...

最新文章

  1. Python入门100题 | 第008题
  2. 解决:AttributeError: module 'pygal' has no attribute 'Worldmap' 问题
  3. 看完这篇,你还不能理解 ‘数据库架构’?趁早回家吧
  4. python 线程池回收_python实现线程池
  5. postman如何导入API.json文件 - 图文教程
  6. Linux I2C App 开发示例
  7. Windows函数:PtrToUlong作用
  8. android 前后同时预览_用上这些官方动态壁纸,让你的 Android 主屏简洁又优雅
  9. Linux下PS命令详解 (转)
  10. java 信号处理模块_GitHub - Astoros-Fung/JavaDsp: 数字信号处理(DSP)方面的Java封装,包含常用的一些处理方法,如滤波、信号变换等等。...
  11. python设置主题背景
  12. golang 支付宝小程序 登陆
  13. 巴菲特致股东的一封信:1996年
  14. 电脑怎么加快网页打开速度?加快网速。
  15. 泰山OFFICE技术讲座:WORD光标出错
  16. 远程网络监视(rmon)与简单网络管理协议(snmp)之间是什么关系
  17. 教培机构如何搭建在线教育网校平台
  18. VMware下安装win10启动后进入Boot Manger界面如何解决
  19. 关于mac地址,请各位大侠帮忙解决
  20. Tailscale 开源版中文部署指南(支持无限设备数、自定义多网段 、自建中继等高级特性)...

热门文章

  1. struct 和typedef struct的区别
  2. 接活,你为啥不行,之懒
  3. 用Delphi内联汇编获取机器码
  4. Objects as Points 论文总结
  5. HGE引擎写的俄罗斯方块程序(附vc源码)[r]
  6. 三句话捋清楚java垃圾收集器
  7. 84.LAMP的apache用户认证,域名跳转,日志文件
  8. 双向循环链表---仿照linux内核实现
  9. 关于Unity中的transform组件(二)
  10. Hadoop 的常用组件一览