zoukankan      html  css  js  c++  java
  • linkin大话数据结构--Set

    • Set 集合
    Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。
    Set 判断两个对象是否相同不是使用 == 运算符,而是根据 equals 方法。也就是说两个对象equals比较返回true,Set集合是不会接受这个两个对象的。
    Set是Collection子接口;Set和Collection基本上一样,一点除外:Set无法记住添加的顺序,不允许包含重复的元素。
    当试图添加两个相同元素进Set集合,添加操作失败,add()方法返回false。

    • 常用子类:
    HashSet:散列存放

    TreeSet:有序存放

    LinkedHashSet:使用链表


    • HashSet
    HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
    HashSet 具有以下特点:

    1,不能保证元素的排列顺序,散列存储:不记录添加顺序,排列顺序时,顺序有可能发生变化

    2,HashSet 不是线程安全的,多个线程访问一个HashSet要使用同步代码

    3,集合元素可以使 null,但是最多只能有一个

    4,当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。

    如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

    5,Hash算法价值体现在速度,可以保证查询快速执行。当从HashSet中访问元素时,HashSet先计算该元素的hashCode(也就是该对象的hashCode方法返回值),然后直接到该HashCode对应的位置取出该元素;
    在这里对象的hashCode就好比是数组里的索引,但是不是索引。

    6,如果需要某个类的对象保存到HashSet集合中,覆写该类的equals()和hashCode()方法,应该尽量保证两个对象通过equals比较返回true时,他们的hashCode返回也相等。

    说到这里,就不得不提object类中的hashCode() 方法:

    HashSet 集合判断两个元素相等的标准:两个对象通过 equals() 方法比较相等,并且两个对象的 hashCode() 方法返回值也相等。如果两个对象通过 equals() 方法返回 true,这两个对象的 hashCode 值也应该相同。重写 hashCode() 方法的基本原则:

    1:在程序运行时,同一个对象多次调用 hashCode() 方法应该返回相同的值

    2:当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode() 方法的返回值也应相等

    3:对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值

    关于hashset值得注意的是:

    package tz.web.main;
    
    import java.util.Iterator;
    import java.util.Set;
    import com.google.common.collect.Sets;
    
    public class Linkin
    {
    	
    	private String name;
    	
    	public Linkin(String name)
    	{
    		super();
    		this.name = name;
    	}
    
    	public String getName()
    	{
    		return name;
    	}
    
    	public void setName(String name)
    	{
    		this.name = name;
    	}
    
    	public static void main(String[] args)
    	{
    		Linkin linkin1 = new Linkin("huhu1");
    		Linkin linkin2 = new Linkin("huhu2");
    		Set<Linkin> set = Sets.newHashSet(linkin1,linkin2);
    		System.out.println(set.size());//2
    		linkin1.setName("LinkinPark");
    		//这里的hashcode值变了,在删除的时候按照这个linkin1的hashcode值去找对象,结果就根本找不见了,所以没有删掉
    		set.remove(linkin1);
    		System.out.println(set.size());//2
    		Iterator<Linkin> it = set.iterator();
    		while(it.hasNext())
    		{
    			it.next();
    			//从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
    			it.remove();
    		}
    		System.out.println(set.size());//1
    	}
    
    	@Override
    	public int hashCode()
    	{
    		final int prime = 31;
    		int result = 1;
    		result = prime * result + ((name == null) ? 0 : name.hashCode());
    		return result;
    	}
    
    	@Override
    	public boolean equals(Object obj)
    	{
    		if (this == obj)
    			return true;
    		if (obj == null)
    			return false;
    		if (getClass() != obj.getClass())
    			return false;
    		Linkin other = (Linkin) obj;
    		if (name == null)
    		{
    			if (other.name != null)
    				return false;
    		}
    		else if (!name.equals(other.name))
    			return false;
    		return true;
    	}
    	
    	
    }
    


    • LinkedHashSet
    LinkedHashSet 是 HashSet 的子类
    LinkedHashSet 集合根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
    LinkedHashSet 性能插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。LinkedHashSet 不允许集合元素重复。


    import java.util.LinkedHashSet;
    import java.util.Set;
    
    
    /**
     *
     * @version 1L
     * @author  LinkinPark 
     * @since   2014-11-10
     * @motto   梦似烟花心似水,同学少年不言情
     * @desc    ^遍历LinkedHashSet集合里面的元素时,LinkedHashSet会按元素的添加顺序来访问集合里面的元素
     */
    public class Linkin 
    {
        
        public static void main(String[] args) 
        {
            Set<String> names = new LinkedHashSet<String>();
            names.add("Binger");
            names.add("LinkinPark");
            //Binger LinkinPark
            for (String string : names) 
            {
                System.out.println(string);
            }
        }
            
            
    
       
    
    }


    • TreeSet


    如果试图把一个对象添加到TreeSet时,该对象必须实现Comparable接口,否则程序会抛出异常。

    使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,参与排序的元素必须是同一类型的,不然会发生ClassCastException异常,

    TreeSet是SortedSet接口唯一的实现,与HashSet相比额外的方法有:
    Comparator comparator() 返回当前Set使用的Comparator 若返回null,表示以自然顺序排序。
    Object first() 返回此 set 中当前第一个(最低)元素。 
    Object last() 返回此 set 中当前最后一个(最高)元素。 
    SortedSet subSet(Object  fromElement, E toElement) 返回此 set 的部子集,其元素从 fromElement(包括)到 toElement(不包括)。 
    SortedSet headSet(Object  toElement) 返回此 set 的部分子集,其元素严格小于 toElement。 

    SortedSet tailSet(Object  fromElement) 返回此 set 的部分子集,其元素大于等于 fromElement。 


    TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。
    • 自然排序
    TreeSet会调用元素的compareTo(Object o)方法来比较元素之间的大小关系,然后将集合里的元素按升序排列.此时需要排序元素的类必须实现Comparable接口,并覆写其int compareTo(Object o)方法;
    该方法用于比较对象,若:obj1,compareTo(obj2),返回0,表示两个对象相等,若返回一个正整数,表示obj1大于obj2,若返回一个负整数,表示obj1小于obj2;

    对于TreeSet集合而言,判断两个对象相等的标准是:compareTo()方法比较返回 0。

    • Comparable 的典型实现:
    BigDecimal、BigInteger 以及所有的数值型对应的包装类:按它们对应的数值大小进行比较

    Character:按字符的 UNICODE 值来进行比较

    Boolean:true 对应的包装类实例大于 false 对应的包装类实例

    String:按字符串中字符的 UNICODE 值进行比较

    Date、Time:后边的时间、日期比前面的时间、日期大


    因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象。当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过 compareTo(Object obj) 方法比较应返回 0。

    import java.util.Set;
    import java.util.TreeSet;
    
    /**
     *
     * @version 1L
     * @author  LinkinPark 
     * @since   2014-11-10
     * @motto   梦似烟花心似水,同学少年不言情
     * @desc    ^如果试图把一个对象添加到TreeSet时,该对象必须实现Comparable接口,否则程序会抛出异常。
     */
    public class Linkin implements Comparable
    {
        private String name;//名字
        private Integer age;//年龄
        
        public Linkin(String name, Integer age) 
        {
            this.name = name;
            this.age = age;
        }
        
        public String getName() 
        {
            return name;
        }
    
        public void setName(String name) 
        {
            this.name = name;
        }
    
        public Integer getAge() 
        {
            return age;
        }
    
        public void setAge(Integer age) 
        {
            this.age = age;
        }
        
        @Override
        public int compareTo(Object obj) 
        {
            Linkin s = (Linkin)obj;
            return this.age - s.age;
        }
    
        public static void main(String[] args) 
        {
            Linkin linkin1 = new Linkin("LinkinPark", 25);
            Linkin linkin2 = new Linkin("Binger", 24);
            Set<Linkin> linkins = new TreeSet<Linkin>();
            linkins.add(linkin1);
            linkins.add(linkin2);
            for (Linkin linkin : linkins) {
                //Binger            LinkinPark
                System.out.println(linkin.getName());
            }
        }
    
       
    
    }

    • 定制排序

    TreeSet的自然排序是根据元素的大小进行升序排序的,若想自己定制排序,比如降序排序,就可以使用Comparator接口了。该接口包含int compare(Object o1,Object o2)方法,用于比较两个对象的大小,比较结果和compareTo方法一致。要实现定制排序,需要在创建TreeSet集合对象时,提供一个一个Comparator对象,该对象里负责集合元素的排序逻辑。如果需要实现定制排序,则需要在创建 TreeSet 集合对象时,提供一个 Comparator 接口的实现类对象。由该 Comparator 对象负责集合元素的排序逻辑。

    import java.util.Comparator;
    import java.util.Set;
    import java.util.TreeSet;
    
    /**
     *
     * @version 1L
     * @author  LinkinPark 
     * @since   2014-11-10
     * @motto   梦似烟花心似水,同学少年不言情
     * @desc    ^
     */
    public class Linkin 
    {
        private String name;//名字
        private Integer age;//年龄
        
        public Linkin(String name, Integer age) 
        {
            this.name = name;
            this.age = age;
        }
        
        public String getName() 
        {
            return name;
        }
    
        public void setName(String name) 
        {
            this.name = name;
        }
    
        public Integer getAge() 
        {
            return age;
        }
    
        public void setAge(Integer age) 
        {
            this.age = age;
        }
        
       
    
        public static void main(String[] args) 
        {
            Linkin linkin1 = new Linkin("LinkinPark", 25);
            Linkin linkin2 = new Linkin("Binger", 24);
            Set<Linkin> linkins = new TreeSet<Linkin>(
                    new Comparator<Linkin>()
                    {   
                        @Override
                        public int compare(Linkin o1, Linkin o2) 
                        {
                            Linkin obj1 = (Linkin) o1;
                            Linkin obj2 = (Linkin) o2;
                            return obj1.getAge() - obj2.getAge();
                        }
                    });
            linkins.add(linkin1);
            linkins.add(linkin2);
            for (Linkin linkin : linkins) {
                //Binger            LinkinPark
                System.out.println(linkin.getName());
            }
        }
    
      }


    各Set实现类的性能分析:
    HashSet和TreeSet是Set的2个典型实现,到底如何选择HashSet和TreeSet呢?HashSet的性能总是比TreeSet好,特别是在最常用的添加,查询元素等操作,因为TreeSet需要额外的红黑树算法来维护集合元素的次序。只有当需要一个保持排序的Set时,才应该使用TreeSet,否则都应该使用HashSet。LinkedHashSet是HashSet的一个子类,对于普通的插入,删除操作,LinkedHashSet总是比HashS慢一点,这是由维护链表所带来的额外开销造成的。不过真是因为有了链表,遍历LinkedHashSet会更快。实际开发中HashSet使用的是比较多的,其他的基本用不到。




  • 相关阅读:
    linux下shell显示-bash-4.1#不显示路径解决方法
    node 封装db层
    json结构更改的方法 把date有数据的分类
    webpack.config.js
    SQLSERVER 跨服 跨库
    sqlserver2005重新安装(安装汇编错误,安装程序无法连接到数据库服务进行服务配置)
    delete语句与reference约束 FK_subplan_job_id冲突问题,导致job无法删除解决办法
    删除作业计划出错(DELETE语句与 REFERENCE约束"FK_subplan_job_id"冲突。)
    jquery判断checked的三种方法
    SQLSERVER和sybase的差异
  • 原文地址:https://www.cnblogs.com/LinkinPark/p/5233144.html
Copyright © 2011-2022 走看看