Hashset散列表

什么是HashSet?

HashSet实现了Set接口,它不允许集合中有重复的值,当我们提到HashSet时,第一件事情就是在将对象存储在HashSet之前,要先确保对象重写equals()和hashCode()方法,这样才能比较对象的值是否相等,以确保set中没有储存相等的对象。如果我们没有重写这两个方法,将会使用这个方法的默认实现。

equals()和hashCode()区别?


equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。

hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的hashCode()方法的计算依赖于对象实例的D(内存地址),故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。

之所以有hashCode方法,是因为在批量的对象比较中,hashCode要比equals来得快,很多集合都用到了hashCode,比如HashTable
 
两个obj,如果equals()相等,hashCode()一定相等。
两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。
所以:
可以考虑在集合中,判断两个对象是否相等的规则是:
第一步,如果hashCode()相等,则查看第二步,否则不相等;
第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。

 

首先equals()hashcode()这两个方法都是从object类中继承过来的。

equals()
是对两个对象的地址值进行的比较(即比较引用是否相同)。

hashCode()
是一个本地方法,它的实现是根据本地机器相关的。

object对象中的 public boolean equals(Object obj),对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true;
注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。如下:
(1)当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true 
(2)当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false
如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等。特别指出利用equals比较八大包装对象
(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它自定义对象时都是比较的引用地址
hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。
这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但不重写hashcode,那么我们再new一个新的对象,
当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致,如在存储散列集合时(如Set类),将会存储了两个值一样的对象,
导致混淆,因此,就也需要重写hashcode()
总而言之,在重写equals()同时,也要重写hashCode()方法

例子:

//重新equals()方法,只有两者的id和name都相同,才认为为同一居民
    public boolean equals(Object obj)
    {
    	if(obj instanceof Resident)
    	{
    		Resident r = (Resident) obj;
    		if(r.id.equals(this.id) && r.name.equals(this.name))
    			return true;
    	}
        return false;
    }
    //重写hashCode()方法,注意HashCode()的覆盖原则
    public int hashCode()
    {
    	return name.hashCode()^id.hashCode();
    }

下面是一个人口普查表(HashSet)

package ch7;

import java.util.HashSet;
import java.util.Iterator;

public class Resident {
    private String id;
    private String name;
    public Resident() {} //无参构造
    public Resident(String id,String name) //有参构造
    {
    	this.id=id;
    	this.name=name;
    }
    public void setName(String name)
    {
    	this.name=name;
    }
    public String getName()
    {
    	return name;
    }
    public void setId(String id)
    {
    	this.id=id;
    }
    public String getId()
    {
    	return id;
    }
    //重新equals()方法,只有两者的id和name都相同,才认为为同一居民
    public boolean equals(Object obj)
    {
    	if(obj instanceof Resident)
    	{
    		Resident r = (Resident) obj;
    		if(r.id.equals(this.id) && r.name.equals(this.name))
    			return true;
    	}
        return false;
    }
    //重写hashCode()方法,注意HashCode()的覆盖原则
    public int hashCode()
    {
    	return name.hashCode()^id.hashCode();
    }
    public String toString()
    {
    	return "身份证号"+id+"姓名"+name;
    }
    public static void main(String[] args) {
		//构建空的set,默认初始容量是16,加载因子0.75
		HashSet<Resident> set = new HashSet<Resident>();		
		//构建空的set,指定初始容量为100,默认加载因子0.75
		//HashSet<Resident> set1 = new HashSet<Resident>(100);	
		//构建空的set,指定初始容量为100,指定加载因子0.70
		//HashSet<Resident> set2 = new HashSet<Resident>(100,0.70F);		
		//居委会交到公安局10条信息
		Resident r1 = new Resident("100000","lily");
		Resident r2 = new Resident("200000","jim");
		Resident r3 = new Resident("300000","beake");
		Resident r4 = new Resident("400000","hevey");
		Resident r5 = new Resident("500000","deke");
		Resident r6 = new Resident("600000","salory");
		//r7与r2身份证号码相同,但名字不同,不是同一人,可以加入集合
		Resident r7 = new Resident("200000","andy");		
		//r8与r5身份证号码相同,但名字不同,
		Resident r8 = new Resident("500000","mike");
		//r9与r1名字相同,但身份证号码不同,不是同一人,可以加入集合
		Resident r9 = new Resident("900000","lily");	
		//r10与r3完全相同,是同一人信息,无法加入集合
		Resident r10 = new Resident("300000","beake");		
		Resident r11 = new Resident("1100000","liyang");
		//向集合中加入对象
		set.add(r1);
		set.add(r2);
		set.add(r3);
		set.add(r4);
		set.add(r5);
		set.add(r6);
		set.add(r7);//可以加入集合
		set.add(r8);//可以加入集合
		set.add(r9);//可以加入集合
		set.add(r10);//r10信息与r3相同,属无效信息,无法加入set中。
		System.out.println("共收集到"+set.size()+"条有效信息如下:");
		int i=1;
		for(Resident r:set)
		{
			System.out.println("第"+i+"条信息"+r);
			i++;
		}
		System.out.println("**********************");
		//身份证号码相同的居民给予另外的号码,名字相同是难免的,没必要改,当然想改也可以
		r7.setId("7000");
		r8.setId("8000");
		r9.setName("sindy");
		//发现r4不是不是本辖区的居民,将信息删除
		set.remove(r4);
		//将更改后的信息输出
		System.out.println("经审核,将身份证号相同的问题解决,并为愿意改名的居民改名,重新统计,本辖区共有"+set.size()+"个居民,信息如下:");
		Iterator<Resident> it = set.iterator();//返回迭代器
		int j=1;
		while(it.hasNext())
		{
		    System.out.println("第"+j+"位居民");
		    System.out.println(it.next());
		}
		System.out.println("**********************");
		
		//查一下辖区内是否有身份证号为600000,叫做salory的居民
		if(set.contains(r6))
		{
			System.out.println("这位名叫"+r6.getName()+"身份证号为"+r6.getId()+"的居民在本辖区");
		}
		else
		{
		    System.out.println("本辖区没有这个居民");
		}
		
		//查一下辖区内是否有身份证号为1100000,叫做liyang的居民
		if(set.contains(r11))
		{
			System.out.println("这位名叫"+r11.getName()+"身份证号"+r11.getId()+"的居民在本辖区");
		}
		else
		{
			System.out.println("本辖区没有这个居民");
		}
	}
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于哈希集(HashSet),它是一种集合数据结构,用于存储唯一的元素,并且不保留特定的顺序。哈希集使用哈希函数将元素映射到一个索引,以便快速访问和搜索。在C语言中,可以使用哈希集来实现类似的功能,但是C本身并没有内置的哈希集数据结构。你可以通过自己实现散列表(Hash Table)或使用第三方库来创建哈希集。 在C中,你可以创建一个散列表来实现哈希集的功能。散列表是一个由键值对组成的数据结构,可以使用一个哈希函数将键映射到一个索引位置。对于哈希集,我们只需要关注键而不需要值。你可以使用一个数组来表示散列表,并使用哈希函数将键映射到数组索引上。 以下是一个简单的示例代码,展示了如何在C中实现一个基本的哈希集: ```c #include <stdio.h> #include <stdbool.h> #define SIZE 10 struct HashSet { int array[SIZE]; }; void initialize(struct HashSet* hashSet) { for (int i = 0; i < SIZE; i++) { hashSet->array[i] = -1; } } int hashFunction(int key) { return key % SIZE; } void insert(struct HashSet* hashSet, int key) { int index = hashFunction(key); while (hashSet->array[index] != -1) { index = (index + 1) % SIZE; } hashSet->array[index] = key; } bool contains(struct HashSet* hashSet, int key) { int index = hashFunction(key); while (hashSet->array[index] != -1) { if (hashSet->array[index] == key) { return true; } index = (index + 1) % SIZE; } return false; } void display(struct HashSet* hashSet) { for (int i = 0; i < SIZE; i++) { if (hashSet->array[i] != -1) { printf("%d ", hashSet->array[i]); } } printf("\n"); } int main() { struct HashSet hashSet; initialize(&hashSet); insert(&hashSet, 5); insert(&hashSet, 10); insert(&hashSet, 15); display(&hashSet); printf("Contains 10: %s\n", contains(&hashSet, 10) ? "True" : "False"); printf("Contains 20: %s\n", contains(&hashSet, 20) ? "True" : "False"); return 0; } ``` 这个示例代码展示了如何使用散列表实现一个简单的哈希集。在这个例子中,我们使用散列函数(取余运算)将键映射到索引,并使用线性探测法解决冲突。你可以根据自己的需求和具体情况进行修改和扩展。希望这可以帮助到你!如果你有任何其他问题,请随时问我。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值