排序及重复元素去重的说明,TreeSet,HashSet

Posted 美好的明天

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序及重复元素去重的说明,TreeSet,HashSet相关的知识,希望对你有一定的参考价值。

先看下面一段代码:

package 类集;
import java.util.Set;
import java.util.TreeSet;
class Person{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String gtoString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
};

public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new TreeSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;
        System.out.println(allSet) ;
    }
};

运行结果:

Exception in thread "main" java.lang.ClassCastException: 类集.Person cannot be cast to java.lang.Comparable
    at java.util.TreeMap.compare(TreeMap.java:1294)
    at java.util.TreeMap.put(TreeMap.java:538)
    at java.util.TreeSet.add(TreeSet.java:255)
    at 类集.test1.main(test1.java:19)

报错。此时没有排序,因为java.lang.comparable类导致。

comparable是进行排序的接口。一个对象数组要想排序需要依靠comparable接口完成。对于treeset一样,要想进行排序,则对象所在的类也要依靠comparable接口

修改如下,要想排序,对象所在的类也要依靠comparable接口(继承之)

package 类集;
import java.util.Set;
import java.util.TreeSet;
class Person implements Comparable<Person>{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String toString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
    public int compareTo(Person per){  //这里需要复习comparable接口的知识
        if(this.age>per.age){
            return 1 ;
        }else if(this.age<per.age){
            return -1 ;
        }else{
            return 0 ;
        }
    }
};
public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new TreeSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;
        System.out.println(allSet) ;
    }
};

输出结果:

[姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:王五;年龄:32, 姓名:赵六;年龄:33]

string类既然可以使用TreeSet排序,则String中肯定已经实现了Comparable接口。

string类定义如下:

public final class Stringextends Objectimplements Serializable, Comparable<String>, CharSequence

此时是可以排序了,但是结果有问题,

[姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:王五;年龄:32, 姓名:赵六;年龄:33]

发现去掉了重复的元素(王五),依靠的是comparable接口完成的。孙七没有加入进来,因为孙七和赵6年龄是完全一样的,而此时的comparable接口比较的只是年龄。

为了保证正确,所有的属性都应该进行比较:改成如下:

package 类集;
import java.util.Set;
import java.util.TreeSet;
class Person implements Comparable<Person>{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String toString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
    public int compareTo(Person per){
        if(this.age>per.age){
            return 1 ;
        }else if(this.age<per.age){
            return -1 ;
        }else{
            return this.name.compareTo(per.name) ;    // 调用String中的compareTo()方法
        }
    }
};
public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new TreeSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;
        System.out.println(allSet) ;
    }
};

输出结果:

[姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:王五;年龄:32, 姓名:孙七;年龄:33, 姓名:赵六;年龄:33]

此时的去重元素并不是真正意义上的重复元素取消

用hashSet试试,hashset不排序。

package 类集;
import java.util.HashSet;
import java.util.Set;
class Person{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public String toString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
};
public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new HashSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;    
        System.out.println(allSet) ;
    }
};

输出结果:

[姓名:王五;年龄:32, 姓名:赵六;年龄:33, 姓名:孙七;年龄:33, 姓名:王五;年龄:32, 姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:王五;年龄:32]

此时并没有去掉重复的元素,该如何取消呢,  

如果要想去掉重复,则需要object类中两个方法帮助。

1,hashcode():表示一个唯一编码,一般通过计算表示。   

2)equals():进行对象的比较操作。

我们需要覆写这两个方法

package 类集;
import java.util.HashSet;
import java.util.Set;
class Person{
    private String name ;
    private int age ;
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    public boolean equals(Object obj){    // 覆写equals,完成对象比较
        if(this==obj){
            return true ;
        }
        if(!(obj instanceof Person)){
            return false ;
        }
        Person p = (Person)obj ;    // 向下转型
        if(this.name.equals(p.name)&&this.age==p.age){
            return true ;
        }else{
            return false ;
        }
    }
    public int hashCode(){
        return this.name.hashCode() * this.age    ; // 自己定义一个公式,如上所写。
    }
    public String toString(){
        return "姓名:" + this.name + ";年龄:" + this.age ;
    }
};
public class test1{
    public static void main(String args[]){
        Set<Person> allSet = new HashSet<Person>() ;
        allSet.add(new Person("张三",30)) ;
        allSet.add(new Person("李四",31)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("王五",32)) ;
        allSet.add(new Person("赵六",33)) ;
        allSet.add(new Person("孙七",33)) ;    
        System.out.println(allSet) ;
    }
};

输出结果:

[姓名:赵六;年龄:33, 姓名:王五;年龄:32, 姓名:张三;年龄:30, 姓名:李四;年龄:31, 姓名:孙七;年龄:33]

此时没有了重复元素

 

如果要想使用Set,必须注意以上两个问题,

1,一个好的类应该覆写object类中的equals(),hashCode(),toString()三个方法,实际上在String()中已经覆写完成了。

2,Set接口依靠hashCode()和equals()完成重复元素的判断,关于这一点,在以后的Map接口中也有体现。

3,TreeSet依靠Comparable完成排序的操作

以上是关于排序及重复元素去重的说明,TreeSet,HashSet的主要内容,如果未能解决你的问题,请参考以下文章

js数组去重的三个方法

P1059 明明的随机数及unique去重的用法

HashSet与TreeSet

用TreeSet和Comparator给list集合元素去重

js实现数组去重的三个方法数组的快速排序

JS数组去重的办法