JAVA数据结构之HashSet和TreeSet总结

Set接口
Set不允许包含相同的元素,如果试图把两个相同元素加入同一个集合中,add方法返回false。

Set判断两个对象相同不是使用==运算符,而是根据equals方法。也就是说,只要两个对象用equals方法比较返回true,Set就不 会接受这两个对象。一般实现Set接口的类有HashSet和TreeSet两种。

Set(集合)不同于动态数组(我们可以把动态数组粗略的看成是List),动态数组里面的元素排列有顺序,而集合里面没有,因此HashSet没有get()方法和set()方法。

HashSet
HashSet是以散列表的形式来实现Set接口的.

HashSet有以下特点

  • 不能保证元素的排列顺序,顺序有可能发生变化
  • 不是同步的
  • 集合元素可以是null,但只能放入一个null(因为集合中的元素不允许重复)

HashSet内部不允许重复,那么HashSet是怎么来判断重复的呢?

当向HashSet结合中存入一个对象时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,hashCode会返回该对象应该存入的物理地址的值,如果在此物理地址上没有其他对象,就可以将该对象存入此物理地址,如果在该位置上已经有了其他对象,那么就会调用equals()方法来比较两个对象的内容是否相同,如果内容相同就说明这两个对象相同,不会继续存储,如果不相同就将对象移到附近的其他物理位置进行存储。 简单的说,HashSet集合判断两个对象相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相 等。 注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对 象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。

如果对象的类型是JAVA内部的类型,那么就不需要重写equals()和hashCode()方法。如果对象的类型不是JAVA内部的类型,那么就需要重写前面提到的两个方法,因为JAVA虚拟机无法判断自定义类的对象的内容如何比较。

示例代码如下:

class Person{
	private String name;
	private int age;
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	public String toString(){
		return name + ":"+age;
	}
	public boolean equals(Object x){
		if(x instanceof Person == false) return false;
		Person p = (Person)x;
		return this.name.equals(p.name)&&this.age == p.age;
	}
	public int hashCode(){
		return name.hashCode() + age;
	}
}
public class HashSetTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		//自定义类
		Set<Person> st = new HashSet<Person>();
		st.add(new Person("zhang", 10));
		st.add(new Person("li", 10));
		st.add(new Person("zhang", 17));
		st.add(new Person("zhang", 10));
		System.out.println(st);
		
		//JAVA内部数据类型
		Set<String> a = new HashSet<String>();
		a.add("abc");
		a.add("xyz");
		a.add("abc");
		System.out.println(a);
	}
}
另外 LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet


TreeSet类
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序 和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较有没有返回0,如果返回0,说明这两个对象相等。
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是 负数,则表明obj1小于obj2。如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法.

那么TreeSet用什么方式来定义两个元素对象是否重复呢?有如下两种不同的方法:

自定义类实现Comparable接口,然后重写CompareTo()方法;

另外一种是聘请外部裁判,实现Comparator接口,调用Compare()方法。

实现实例如下:

import java.util.*;

/*
 class Person implements Comparable
 {
 private String name;
 private int age;
 public Person(String name, int age)
 {
 this.name = name;
 this.age = age;
 }
 @Override
 public int compareTo(Object o) {
 // TODO Auto-generated method stub
 if (o instanceof Person == false) return 0;
 Person p = (Person)o;
 int t = this.name.compareTo(p.name);
 if(t != 0)return t;
 return this.age - p.age;
 }

 public String toString(){
 return name + ":" + age;
 }
 }
 */
class Person {
	private String name;
	private int age;

	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	public String toString() {
		return name + ":" + age;
	}
	
	public String getName(){
		return this.name;
	}
	
	public int getAge(){
		return this.age;
	}
}

class K implements Comparator {

	@Override
	public int compare(Object a, Object b) {
		// TODO Auto-generated method stub
		if (a instanceof Person == false || b instanceof Person == false)
			return 0;// 因为如果a,b都不是Person类,那么已经超出了该方法判定的范围,我们只能假定其相等,0表示相等
		Person p1 = (Person) a;
		Person p2 = (Person) b;
		int t = p2.getName().compareTo(p2.getName());
		if (t != 0) return t;
		return p1.getAge() - p2.getAge();
	}

}

public class TreeSetTEST {
	public static void main(String[] args) {
		// Set<Person> a = new TreeSet<Person>();
		Set<Person> a = new TreeSet<Person>(new K());
		a.add(new Person("hao", 10));
		a.add(new Person("hao", 20));
		a.add(new Person("hao", 30));
		a.add(new Person("hao", 10));
		a.add(new Person("zhang", 10));
		a.add(new Person("zhang", 11));
		a.add(new Person("zhang", 20));
		a.add(new Person("li", 40));

		System.out.println(a);
	}

}


  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值