zoukankan      html  css  js  c++  java
  • Java集合框架—Set


    集合框架 Set的特点:无序,不可以重复元素。


    (1)HashSet:数据结构是哈希表。线程是非同步的。
                  保证元素唯一性的原理:判断元素的hashCode值是否相同。
                  如果相同,还会继续判断元素的equals方法,是否为true。


    (2)TreeSet:可以对Set集合中的元素进行排序。
                   底层数据结构是二叉树。
                   保证元素唯一性的依据:compareTo方法return 0。

    一、HashSet相关知识

        HashSet中的元素不可以重复,如果重复添加,则只会显示一个。

    原理如下:

    HashSet:底层数据结构是哈希表。是线程不安全的。不同步。

     

    HashSet是如何保证元素唯一性的呢?
    答:是通过元素的两个方法,hashCode和equals来完成。
    如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashcode值不同,不会调用equals。

    *******对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法**********


    代码1:

    package com.package2;
    
    import java.util.*;
    
    public class HashSet222 
    {
    
    	public static void main(String[] args) 
    	{
    		
    		HashSet hs = new HashSet();
    
    		hs.add("java01");
    		hs.add("java01");
    		hs.add("java02");
    		hs.add("java03");
    		hs.add("java03");
    		hs.add("java04");
    
    		Iterator it = hs.iterator();
    
    		while(it.hasNext())
    		{
    			System.out.println(it.next());
    		}
    	}
    }
    
    此demo将String类型的字符串添加进去,并且没有重复,结果如下:

    java04
    java02
    java03
    java01

    由此我们可以断定,String类已经实现了hashcode()方法和equals()方法。打开,帮助文档,确实(这不是废话么^_^)

    但是,如果我们要将自定义的元素add进HashSet中,则必须定义其自己的hashcode()方法和equals()方法。如下所示:

    代码2:

    package com.package2;
    import java.util.*;
    public class HashSet3 
    {
    	public static void main(String[] args) 
    	{
    		HashSet hs = new HashSet();
    
    		hs.add(new Person("a1",11));
    		hs.add(new Person("a2",12));
    		hs.add(new Person("a3",13));
    		hs.add(new Person("a2",12));
    		hs.add(new Person("a4",14));
    		
    
    		Iterator it = hs.iterator();
    
    		while(it.hasNext())
    		{
    			Person p = (Person)it.next();
    			System.out.println(p.getName()+"::"+p.getAge());
    		}
    	}
    }
    class Person
    {
    	private String name;
    	private int age;
    	Person(String name,int age)
    	{
    		this.name = name;
    		this.age = age;
    	}
    	
    	public int hashCode()
    	{
    		System.out.println(this.name+"....hashCode");
    		return name.hashCode()+age*37;  //保证此元素的返回值尽量不一致。
    	}
    
    	public boolean equals(Object obj)
    	{
    
    		if(!(obj instanceof Person))
    			return false;
    
    		Person p = (Person)obj;
    		System.out.println(this.name+"...equals.."+p.name);
    
    		return this.name.equals(p.name) && this.age == p.age;
    	}
    
    	
    	public String getName()
    	{
    		return name;
    	}
    	public int getAge()
    	{
    		return age;
    	}
    }
    
    输出结果如下:

    a1....hashCode
    a2....hashCode
    a3....hashCode
    a2....hashCode
    a2...equals..a2
    a4....hashCode
    a1::11
    a3::13
    a2::12
    a4::14

    由此可以看出,将元素add时,会首先调用元素的hashcode()方法,当返回值重复时,会调用其equals方法。缺少任何一种方法都构不成一个HashSet集合。



    二、TreeSet相关知识

    TreeSet有俩种排序方式。

    TreeSet排序的第一种方式:让元素自身具备比较性。
    步骤:将add进TreeSet中的元素实现Comparable接口,并且覆盖compareTo方法。这种顺序也是元素的自然顺序,或者叫做默认顺序。

    TreeSet的第二种排序方式。当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性(即利用其另一种构造函数建立对象)。在集合初始化时,就有了比较方式。

    步骤:利用某个指定类实现Comparator接口,并且覆盖compare()方法,则此类会成为一个具备比较方法的类。在建立TreeSet的时候,将此类对象传入其中。

    则此时,添加进TreeSet中的元素可按照指定比较方法进行排序。


    下边举例演示俩种排序方式。

    排序方式一:代码1:

    package com.package1;
    
    import java.util.*;
    
    public class TreeSettest {
    
    	public static void main(String[] args) {
    		//创建对象
    		TreeSet ts=new TreeSet();
    		
    		//添加元素
    		ts.add("abcjjj");
    		ts.add("abb");
    		ts.add("daccc");
    		ts.add("gfg");
    		ts.add("geee");
    		ts.add("r");
    		
    		//进行迭代
    		Iterator it=ts.iterator();
    		
    		//循环取出元素
    		while(it.hasNext())
    		{
    			System.out.println(it.next());
    		}
    
    	}
    
    }
    
    输出结果如下:

    abb
    abcjjj
    daccc
    geee
    gfg
    r

    由此可见,此时元素具备可比性,即按照其自然顺序进行排序。打开帮助文档,我们可以清晰的发现String已经实现了Comparable接口,并且已经覆盖了compareTo(),“这不是废话么^_^”,如图所示:




    ps……如果我们要往TreeSet里添加的元素是自己刚刚定义的,我们也可以自己定义该元素的类实现Comparator接口,并且覆盖compareTo()方法,如下所示:代码2:

    package com.package1;
    
    import java.util.*;
    
    class Student implements Comparable//该接口强制让学生具备比较性。
    {
    	private String name;
    	private int age;
    
    	Student(String name,int age)
    	{
    		this.name = name;
    		this.age = age;
    	}
    
    	public int compareTo(Object obj)
    	{
    
    		//return 0;
    		
    		if(!(obj instanceof Student))
    			throw new RuntimeException("不是学生对象");
    		Student s = (Student)obj;
    
    		//System.out.println(this.name+"....compareto....."+s.name);
    		if(this.age>s.age)
    			return 1;
    		if(this.age==s.age)
    		{
    			return this.name.compareTo(s.name);
    		}
    		return -1;
    		/**/
    	}
    
    	public String getName()
    	{
    		return name;
    
    	}
    	public int getAge()
    	{
    		return age;
    	}
    }
    public class TreeSet2 
    {
    	public static void main(String[] args) 
    	{
    		TreeSet ts = new TreeSet();
    
    		ts.add(new Student("lisi02",22));
    		ts.add(new Student("lisi02",21));
    		ts.add(new Student("lisi007",20));
    		ts.add(new Student("lisi09",19));
    		ts.add(new Student("lisi06",18));
    		ts.add(new Student("lisi06",18));
    		ts.add(new Student("lisi007",29));
    		//ts.add(new Student("lisi007",20));
    		//ts.add(new Student("lisi01",40));
    
    		Iterator it = ts.iterator();
    		while(it.hasNext())
    		{
    			Student stu = (Student)it.next();
    			System.out.println(stu.getName()+"..."+stu.getAge());
    		}
    	}
    }
    

    结果如下:

    lisi06...18
    lisi09...19
    lisi007...20
    lisi02...21
    lisi02...22
    lisi007...29

    此例子将学生元素,强行按照年龄来排序,这就是我们想要的排序方式。


    第二种排序如下:

    还是刚刚代码1的例子,我们使用第二种排序方式,使得String类型的元素按照长度来排序。

    代码3:

    /*
     * 使元素按照长度来排序,若长度相同,则按照自然排序。
     */
    public class TreeSettest {
    
    	public static void main(String[] args) {
    		//创建对象
    		TreeSet ts=new TreeSet(new MyCompare());
    		
    		//添加元素
    		ts.add("abc");
    		ts.add("bcc");
    		ts.add("das");
    		ts.add("bcde");
    		ts.add("asdfg");
    		ts.add("befqfca");
    		
    		//进行迭代
    		Iterator it=ts.iterator();
    		
    		//循环取出元素
    		while(it.hasNext())
    		{
    			System.out.println(it.next());
    		}
    
    	}
    
    }
    
    //定义一个类实现Comparator接口,并且覆盖compare()方法。
    class MyCompare implements Comparator
    {
    
    	@Override
    	public int compare(Object o1, Object o2) {
    		//进行强制类型转换
    		String s1=(String) o1;
    		String s2=(String) o2;
    		
    		//进行比较
    		if(s1.length()>s2.length())
    			return 1;
    		if(s1.length()<s2.length())
    			return -1;
    		if(s1.length()==s2.length())
    		{
    			return s1.compareTo(s2);
    		}
    		return 0;
    	}
    }
    
    结果如下:

    abc
    bcc
    das
    bcde
    asdfg
    befqfca

    此种情况下,我们不方便修改源代码,而只需要修改比较方法时,我们就可以自己创建一个比较器。在建立TreeSet时,将比较器传入即可使元素按照特定比较方式输出。


    总结:

    Comparable(方式一)接口和Compartor(方式二)接口的比较:

     

             两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但

    是需要修改源代码。

     

           用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把

    比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其

    可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。









  • 相关阅读:
    树套树+【UVALive】6709 Mosaic 二维线段树
    汇编实验1. 计算1+2+3+…+10,将结果显示在屏幕上。4
    Tinkoff Internship Warmup Round 2018 and Codeforces Round #475 (Div. 2) D. Destruction of a Tree
    HDU 4417 Super Mario主席树
    spoj+B
    2018-2019赛季多校联合新生训练赛第五场(2018/12/14)补题题解
    迷宫问题 POJ
    浅谈二分搜索与二分查找
    Moving Tables POJ
    Humidex POJ
  • 原文地址:https://www.cnblogs.com/lanzhi/p/6467329.html
Copyright © 2011-2022 走看看