GVKun编程网logo

HashSet上的迭代成本还取决于支持映射的容量吗?(hashset迭代器)

27

本文将介绍HashSet上的迭代成本还取决于支持映射的容量吗?的详细情况,特别是关于hashset迭代器的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些

本文将介绍HashSet上的迭代成本还取决于支持映射的容量吗?的详细情况,特别是关于hashset迭代器的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于9 HashSet HashCode 迭代器 TreeSet Colletions类 HashMap、c# – GetHashCode应该取决于类型吗?、c# – LINQ在HashSet上的ForEach?、Day65-每日一道Java面试题-HashMap 和 HashSet区别、HashSet如何检查重复的知识。

本文目录一览:

HashSet上的迭代成本还取决于支持映射的容量吗?(hashset迭代器)

HashSet上的迭代成本还取决于支持映射的容量吗?(hashset迭代器)

从HashSet的JavaDocs中:

该类为基本操作(添加,删除,包含和大小)提供恒定的时间性能,假设哈希函数将元素正确地分散在存储桶中。遍历此集合需要的时间与HashSet实例的大小(元素的数量)加上后备HashMap实例的“容量”(存储桶的数量)之和成比例。因此,如果迭代性能很重要,则不要将初始容量设置得过高(或负载因子过低),这一点非常重要

为什么迭代需要的时间与总和(集合中元素的数量+支持映射的容量)成比例,而不仅与集合本身中的元素数量成正比?

答案1

小编典典

HashSet使用HashMap元素作为地图键来实现。由于地图具有定义数量的存储桶,可以包含一个或多个元素,因此迭代需要检查每个存储桶,无论是否包含元素。

9 HashSet HashCode 迭代器 TreeSet Colletions类 HashMap

9 HashSet HashCode 迭代器 TreeSet Colletions类 HashMap


1. 当向ArrayList添加一个对象时,实际上就是将该对象放置到了ArrayList底层所维护的数组当中;当向LinkedList中添加一个对象时,实际上LinkedList内部会生成一个Node对象,该Node对象的结构为
void linkLast(E e) {
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }
private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

其中的Object类型的元素element就是我们向LinkedList中所添加的元素,然后Node又构造好了向前与向后的引用previous、next,最后将生成的这个Node对象加入到了链表当中。换句话说,LinkedList中所维护的是一个个的Node对象。

2. 关于Object类的equals方法的特点

a) 自反性:x.equals(x)应该返回true
b) 对称性:x.equals(y)为true,那么y.equals(x)也为true。
c) 传递性:x.equals(y)为 true并且y.equals(z)为true,那么x.equals(z)也应该为true。
d) 一致性:x.equals(y)的第一次调用为true,那么x.equals(y)的第二次、第三次、第n次调用也应该为true,前提条件是在比较之间没有修改x也没有修改y。

e) 对于非空引用x,x.equals(null)返回false。


3. 关于Object类的hashCode()方法的特点:


a) 在Java应用的一次执行过程当中,对于同一个对象的hashCode方法的多次调用,他们应该返回同样的值(前提是该对象的信息没有发生变化)。


b) 对于两个对象来说,如果使用equals方法比较返回true,那么这两个对象的hashCode值一定是相同的


c) 对于两个对象来说,如果使用equals方法比较返回false,那么这两个对象hashCode值不要求一定不同(可以相同,可以不同),但是如果不同则可以提高应用的性能。


d) 对于Object类来说,不同的Object对象的hashCode值是不同的(Object类的hashCode值表示的是对象的地址)。

4. 当使用HashSet时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code值是否与增加的对象的hash code值一致;如果不一致,直接加进去;如果一致,再进行equals方法的比较,equals方法如果返回true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。

HashSet set = new HashSet();
		
//		set.add(new People("zhangsan"));
//		set.add(new People("lisi"));
//		set.add(new People("zhangsan"));
		
//		People p1 = new People("zhangsan");
//		
//		set.add(p1);
//		set.add(p1);
		
		String s1 = new String("a");
		String s2 = new String("a");
		
		System.out.println("hash code: " + (s1.hashCode() == s2.hashCode()));
		
		set.add(s1);
		set.add(s2);
		
		System.out.println(set)

String的HashCode方法:

/**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]  String类型的HasCode计算法
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }



5. 如果我们重写一个类的equals方法,那么也要重写hashCode方法,反之亦然。

重写HashCode是为了在集合中应用。

Eclipse 自动重写HashCode()和equals();Source->Generate....

迭代器:(类似于GIS里面的cursor)

通常希望循环通过类集中的元素。例如,可能会希望显示每一个元素。到目前为止,处理这个问题的最简单方法是使用iterator,iterator是一个或者实现Iterator或者实现ListIterator接口的对象。Iterator可以完成循环通过类集,从而获得或删除元素。ListIterator扩展Iterator,允许双向遍历列表,并可以修改单元.


在通过迭代函数访问类集之前,必须得到一个迭代函数。每一个Collection类都提供一个iterator()函数,该函数返回一个对类集头的迭代函数。通过使用这个迭代函数对象,可以访问类集中的每一个元素,一次一个元素。通常,使用迭代函数循环通过类集的内容,步骤如下
–1. 通过调用类集的iterator( )方法获得对类集头的迭代函数。
–2. 建立一个调用hasNext( )方法的循环,只要hasNext( )返回true,就进行循环迭代。
–3. 在循环内部,通过调用next( )方法来得到每一个元素

public static void main(String[] args)
	{
		HashSet hash = new HashSet();
		hash.add("I");
		hash.add(" Miss ");
		hash.add(" You ");
		hash.add(" WangBingJia");
		Iterator iterator = hash.iterator();
		while (iterator.hasNext())
		{
			System.out.println(iterator.next().toString());
		}
	}
TreeSet 有顺序的集合,使用前通常需要定义 Comparator,即实现Comparator接口中Compare方法

public class TreeSetTest
{
	
	public static void main(String[] args)
	{
		Compare compare=new Compare();
		TreeSet ts=new TreeSet(compare);
		ts.add((new Student(10)));
		ts.add(new Student(20));
		System.out.println(ts);
		
	}
	

}
class Compare implements Comparator
{

	@Override
	public int compare(Object o1, Object o2)
	{
		// TODO Auto-generated method stub
		Student s1=(Student) o1;
		Student s2=(Student) o2;
		if (s1 .socore<s2.socore)
		{
			return -1;
		}
		else if (s1 .socore==s2.socore)
		{
			return 0;
		}
		else {
			return 1;
		}
		
	}
	}
class Student
{
	 int socore;
	Student(int socore){
		this.socore=socore;
	}
	@Override
	public String toString()
	{
		// TODO Auto-generated method stub
		return Integer.toString(socore);
	}
	}

Collections类的一些静态方法

reverseOrder() 反序排列

shuffle  打乱顺序

public static void main(String[] args)
	{
		LinkedList list = new LinkedList();
		
		list.add(new Integer(-8));
		list.add(new Integer(20));
		list.add(new Integer(-20));
		list.add(new Integer(8));
		
		Comparator r = Collections.reverseOrder();
		
		Collections.sort(list, r);
		
		for(Iterator iter = list.iterator(); iter.hasNext();)
		{
			System.out.println(iter.next() + " ");
		}
		
		System.out.println();
		
		Collections.shuffle(list);
		
		for(Iterator iter = list.iterator(); iter.hasNext();)
		{
			System.out.println(iter.next() + " ");
		}
		
		System.out.println("minimum value: " + Collections.min(list));
		System.out.println("maximum value: " + Collections.max(list));
	}

6. Map(映射):实现类HashMap

Map的keySet()方法会返回key的集合,因为Map的键是不能重复的因此keySet()方法的返回类型是Set;而Map的值是可以重复的,因此values()方法的返回类型是Collection,可以容纳重复的元素。


HashMap hashMap=new HashMap();
hashMap.put("a","Bingjia");
hashMap.put("a","I");
hashMap.put("b","Bingjia");
System.out.println(hashMap);


通过hashMap的KeySet方法,实现对hashMap的遍历

Set set=hMap.keySet();
		Iterator iterator=set.iterator();
		while (iterator.hasNext())
		{
			System.out.println(hMap.get(iterator.next()));
			
		}

HashMap中储存的是一个一个Map.Entry对象,每一个Map.Entry维护了一对key和value

所以对HashMap的遍历可以遍历取出Map.Entry

hMap.put("1","I");
		hMap.put("2","Miss");
		hMap.put("3","You");
		hMap.put("4","WangBingjia");
		
		
		Set set =hMap.entrySet();
		Iterator iterator=set.iterator();
		while (iterator.hasNext())
		{
			Map.Entry entry=(Entry) iterator.next();
			System.out.println("key "+entry.getKey()+" values "+ entry.getValue());
			
		}





利用hashMap统计数字

HashMap hMap=new HashMap();
for(int i=0;i<args.length;i++)
{
if (hMap.containsKey(args[i]))
{
Object o1= hMap.get(args[i]);
Integer integer=(Integer )o1;
integer ++;
hMap.put(args[i],integer);

}
else {
hMap.put(args[i],1);
}
}
System.out.println(hMap);





c# – GetHashCode应该取决于类型吗?

c# – GetHashCode应该取决于类型吗?

首先,我使用的是描述的GetHashCode算法,here.现在,想象下面的(人为的)示例:

class Foo
{
    public Foo(int intValue,double doubleValue)
    {
        this.IntValue = intValue;
        this.DoubleValue = doubleValue;
    }

    public int IntValue { get; private set; }
    public double DoubleValue { get; private set; }

    public override int GetHashCode()
    {
        unchecked
        {
            int hash = 17;

            hash = hash * 23 + IntValue.GetHashCode();
            hash = hash * 23 + DoubleValue.GetHashCode();
            return hash;
        }

    }
}

class DerivedFoo : Foo
{
    public DerivedFoo(int intValue,double doubleValue)
       : base(intValue,doubleValue)
    {

    }
}

如果我有一个Foo和一个DerivedFoo,每个属性具有相同的值,那么它们将具有相同的哈希码.这意味着我可以拥有HashSet< Foo>或者在Linq中使用distinct方法,这两个实例将被视为相同.

我可能只是误解了GetHashCode的使用,但我希望这两个实例有不同的哈希码.这是一个无效的期望还是GetHashCode应该在计算中使用类型? (或者DerivedClass是否也会覆盖GetHashCode)?

附:我意识到关于这个主题的SO有很多很多问题,但是我没有发现直接回答这个问题的问题.

解决方法

GetHashCode()不应该保证唯一性(尽管如果尽可能唯一,它有助于提高性能).

GetHashCode()的主要规则是等效对象必须具有相同的哈希代码,但这并不意味着非等效对象不能具有相同的哈希代码.

如果两个对象具有相同的哈希码,则调用Equals()方法以查看它们是否相同.由于类型不同(取决于你如何编码你的Equals过载),它们将不相等,因此它会没问题.

即使您对每种类型都有不同的哈希码算法,仍然总是存在冲突的可能性,因此也需要进行Equals()检查.

现在给出上面的示例,您不实现Equals(),这将使每个对象都不同,无论哈希代码如何,因为对象的Equals()的默认实现是引用相等性检查.

如果还没有,请继续为每个类型重写Equals()(如果你愿意,可以继承你的GetHashCode()实现,或者有新的类型),你可以确保它的类型在声明它们相等之前,compare-to对象是相同的.并确保始终实现Equals()和GetHashCode(),以便:

> Equals()对象必须具有相同的GetHashCode()结果.>具有不同GetHashCode()的对象不能是Equals().

c# – LINQ在HashSet上的ForEach?

c# – LINQ在HashSet上的ForEach?

我很好奇是什么限制必须让设计决定不让HashSet能够使用LINQ的ForEach查询.

这两种实现的幕后实际情况有何不同:

var myHashSet = new HashSet<T>;
foreach( var item in myHashSet ) { do.Stuff(); }

VS

var myHashSet = new HashSet<T>;
myHashSet.ForEach( item => do.Stuff(); }

我(非常)确定这只是因为HashSet没有实现IEnumerable – 但是正常的ForEach循环做什么不同会使HashSet更多地支持它?

谢谢

解决方法

LINQ没有ForEach.仅列表< T> class有一个ForEach方法.

值得注意的是,HashSet确实实现了IEnumerable< T>.

请记住,LINQ代表语言集成查询.它用于查询数据集合. ForEach与查询无关.它只是循环数据.因此它确实不属于LINQ.

Day65-每日一道Java面试题-HashMap 和 HashSet区别、HashSet如何检查重复

Day65-每日一道Java面试题-HashMap 和 HashSet区别、HashSet如何检查重复

一、HashMap 和 HashSet区别

如果你看过 HashSet 源码的话就应该知道:HashSet 底层就是基于 HashMap 实现的。(HashSet 的源码非常非常少,因为除了 clone()、writeObject()、readobject()是 HashSet 自己不得不实现之外,其他方法都是直接调用 HashMap 中的方法。

HashMap HashSet
实现了 Map 接口 实现 Set 接口
存储键值对 仅存储对象
调用 put()向 map 中添加元素 调用 add()方法向 Set 中添加元素
HashMap 使用键(Key)计算 hashcode HashSet 使用成员对象来计算 hashcode 值,对于两个对象来说 hashcode 可能相同,所以 equals()方法用来判断对象的相等性

二、HashSet如何检查重复

以下内容摘《Head first java》第二版:

当你把对象加入HashSet时,HashSet 会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让加入操作成功。

hashCode()与 equals() 的相关规定:

  1. 如果两个对象相等,则 hashcode 一定也是相同的
  2. 两个对象相等,对两个 equals() 方法返回 true
  3. 两个对象有相同的 hashcode 值,它们也不一定是相等的
    综上,如果一个类的 equals() 方法被覆盖过,则 hashCode() 方法也必须被覆盖。

hashCode() 的默认⾏为是对堆上的对象产⽣独特值。如果没有重写 hashCode() ,即使通过 equals() 判断为相同的两个对象,在加入 HashSet 时,也不会被 HashSet 认为是重复对象。

import java.util.HashSet;

public class People {
    String idCard;

    public People(String idCard) {
        this.idCard = idCard;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        People people = (People) o;
        return idCard.equals(people.idCard);
    }

    public static void main(String[] args) {
        People a = new People("a");
        People a1 = new People("a");
        // output: true
        System.out.println(a.equals(a1));

        HashSet<People> set = new HashSet<>();
        set.add(a);
        set.add(a1);
        // output: 2
        System.out.println(set.size());
    }
}

今天的关于HashSet上的迭代成本还取决于支持映射的容量吗?hashset迭代器的分享已经结束,谢谢您的关注,如果想了解更多关于9 HashSet HashCode 迭代器 TreeSet Colletions类 HashMap、c# – GetHashCode应该取决于类型吗?、c# – LINQ在HashSet上的ForEach?、Day65-每日一道Java面试题-HashMap 和 HashSet区别、HashSet如何检查重复的相关知识,请在本站进行查询。

本文标签: