黑马程序员--07.集合框架--07.【TreeSet】【TreeSet底层的二叉树】
2013-07-25 17:56
330 查看
集合框架--7
TreeSet概述 TreeSet底层的二叉树
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------1. TreeSet概述
(1). Set常用子类的回顾[1]. Set集合具有无序性和唯一性
[2]. HashSet 底层数据结构是哈希表,线程非同步。
保证元素唯一性的办法就是调用元素的hashCode方法和equals方法
[3]. TreeSet 底层数据结构是二叉树,线程非同步。
【TreeSet的优势】可以对元素进行排序
【TreeSet的无序性】由于TreeSet会对添加的元素进行排序,所以这一般会和添加元素的顺序不一致,这样就会导致从TreeSet中取出元素的顺序和存入时候的顺序不一致。所以说是无序的。
(2). TreeSet产生的一个异常
【产生异常的原因】
TreeSet能够进行排序。但是自定义的Person类并没有给出排序的规则。即普通的自定义类不具备排序的功能,所以要实现Comparable接口。
(3). 让TreeSet中存储的元素具有比较性 ----实现Comparable接口
[1]. Comparable接口的原型
public
interface Comparable<T>{
public
int compareTo(T o);
}
Comparable接口仅仅有一个方法需要实现,compareTo方法需要被子类实现。
[2]. Comparable接口的描述:
Compares this object with the specifiedobject for order.
Returns a
negative integer, zero, or apositive integer as this object is less
than,equal to, or greater than the specified object
翻译下:因为这个对象(指的是实现Comparable接口的类的对象) 小于,等于或者大于指定对象,所以,返回一个负数,0或者一个正数。
[注意]
当compareTo方法返回0的时候,表示这两个对象相同。
依据Set接口的特点,相同的对象是不能出现在一个Set集合中的,否则有悖于Set集合无序性。
【结论】当两个对象通过compareTo的比较返回0的时候,从compareTo方法参数中接受的对象不能被存入TreeSet集合。
[2]. 示例代码:
import java.util.*;
class Student implements Comparable
{
private String name;
private int age;
public Student(String name, int age){
this.name =name;
this.age =age;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name =name;
}
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age = age;
}
public String toString(){
return this.name+"::::"+ this.age;
}
public int compareTo(Object o){
if(!(o instanceof Student))
throw new RuntimeException("This is not a instance of Class \"Student\" ");
Students =(Student)o;
sop(this.name +"......compareTo...."+ s.name);
if(this.age > s.age)
return 1;
else if(this.age ==s.age)
return 0;
return -1;
}
public static void sop(Object o){
System.out.println(o);
}
}
class TreeSetDemo
{
public static void sop(Object o){
System.out.println(o);
}
public static void main(String[] args){
TreeSetts =new TreeSet();
ts.add(new Student("lisi02", 22));
ts.add(new Student("lisi007", 20));
ts.add(new Student("lisi09", 19));
Iteratorit =ts.iterator();
while(it.hasNext()){
sop(it.next());
}
}
}
打印结果:
除了第一个元素添加进来的时候,没有调用compareTo()方法,其余的元素添加进来的时候,TreeSet都调用了这些元素的compareTo方法。
输出的时候,这些元素都被按照年龄来排序输出。
(4). 细化排序的条件
[1]. 现在将数据变化一下,多加入一个元素:
ts.add(new Student("lisi02", 22));
ts.add(new Student("lisi007", 20));
ts.add(new Student("lisi09", 19));
ts.add(new Student("lisi08", 19));
也就是添加了两个年龄一样的Student对象。
【产生的问题】发现lisi08在被TreeSet添加的时候,确实调用了这个元素的compareTo方法。但是最后TreeSet集合中却没有加入这个元素。
【产生的原因】因为当;lisi08......compareTo....lisi09打印的时候,说明这两个元素进行了比较。但是,比较的时候,两者的年龄均为19,所以else
if(this.age ==s.age)这个分支执行,返回0。
返回0就意味着TreeSet判定这两个对象是一样的,就不能被存入集合中。
[2]. 细化判断条件
【要点】当主要条件相同的时候,一定要判断次要条件。
这里面,只有当Student类的年龄和姓名都一样的时候,才应该被视为是同一个对象。所以当年龄相同的时候,应该继续判断这两个对象的姓名是否相同。
修改代码示例:
public int compareTo(Object o){
if(!(o instanceof Student))
throw new RuntimeException("This is not a instance of Class \"Student\" ");
Students =(Student)o;
sop(this.name +"......compareTo...."+ s.name);
if(this.age > s.age)
return 1;
else if(this.age ==s.age)
return this.name.compareTo(s.getName());
return -1;
}
打印结果:
可以看到年龄相同但是姓名不同的lisi08和lisi09都被成功地添加到TreeSet集合中来。
2. TreeSet底层的二叉树
1). TreeSet的二叉树存储元素的过程
(1). 示例代码TreeSet ts =new TreeSet();
ts.add(new Student("lisi02", 22));
ts.add(new Student("lisi007", 20));
ts.add(new Student("lisi09", 19));
ts.add(new Student("lisi08", 19));
ts.add(new Student("lisi11", 40));
ts.add(new Student("lisi16", 30));
ts.add(new Student("lisi12", 36));
ts.add(new Student("lisi10", 29));
ts.add(new Student("lisi22", 90));
(2). 存储过程分析
[1]. 先存入一个元素22。
[2]. 20进来时,调用自身的compareTo方法,要和22比较。发现20 <22,compareTo返回负数,此时存入二叉树的左边。如图:
[3]. 19进来,先和22比较一下。19 <22,返回负数。此时19往22的左边走。22的左边还有一个20,再次比较一下:19 < 20, 19也放在20的左边。如图:
[4]. 有一个lisi08—19的元素要加入进来。分别和22, 20比较之后,compareTo方法都返回负数。这个元素要放在22, 20的左边。当lisi08—19和已存在的lisi09—19比较的时候,TreeSet发现两者的年龄相同,又一次调用return
this.name.compareTo(s.getName()); 结果lisi08—19所在的compareTo返回负数(字符串lisi08 < lisi09)。则此时lisi08—19仍然放到lisi09—19的左边。如图:
[5]. "lisi11", 40进来。和22比较之后,40 > 22, compareTo返回正数。放在22的右边。【这样减少了很多次的比较】。如图:
[6].30 >22--->放在22的右边 30 <40--->放在40的左边。如图:
[7].36 >22--->放在22的右边 36 <40--->放在40的左边 36 > 30--->放在30的右边。如图:
[8].29 >22--->放在22的右边 29 <40--->放在40的左边 29 < 30--->放在30的左边。如图:
[9].90 >22--->放在22的右边 90 > 40--->放在40的右边。如图:
打印结果:【TreeSet内部存在了优化, 将lisi007---20作为了根节点】
【二叉树的优势】减少了比较的次数。
(3). 取出过程分析
[1]. 根元素的左叉的数 <右叉的数 先遍历左边
[2]. 再遍历右边
----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------
相关文章推荐
- 黑马程序员--07.集合框架--08.【TreeSet的Comparator排序】【TreeSet总结】
- 黑马程序员_JAVA笔记14——集合框架(List、HashSet、TreeSet)
- Java基础---集合框架---迭代器、ListIterator、Vector中枚举、LinkedList、ArrayList、HashSet、TreeSet、二叉树、Comparator
- Java基础---集合框架---迭代器、ListIterator、Vector中枚举、LinkedList、ArrayList、HashSet、TreeSet、二叉树、Comparator
- 集合框架_TreeSet保证元素唯一性和自然排序的原理和图解(二叉树结构)
- 黑马程序员--07.集合框架--04.List实现子类【ArrayList】【LinkedList】【Vector】
- 黑马程序员_学习笔记:10) 集合框架2:Set(HashSet、TreeSet)、Map(Hashtable、HashMap、TreeMap)、Collections、Arrays
- 集合框架_07 _TreeSet
- 黑马程序员--07.集合框架--10.【Map.Entry内存结构】【Map集合的迭代方式】
- 黑马程序员--07.集合框架--03.【列表List集合的共性方法】【列表迭代器ListIterator】
- 【黑马程序员】Java基础07:集合框架与典型应用
- 黑马程序员——17,集合,TreeSet,二叉树,泛型
- 黑马程序员--07.集合框架--01.【Collection接口】
- 黑马程序员--07.集合框架--06.【HashSet】
- 黑马程序员------集合框架(No.3)(Set、TreeSet、HashSet)
- 黑马程序员--07.集合框架--02.【迭代器Iterator】
- 黑马程序员--07.集合框架--09.【集合Map】
- 黑马程序员--07.集合框架--05.【集合Set】【哈希表】
- 黑马程序员--07.集合框架--02. 重写HashCode的内存变化过程以及两种重写hashCode方式的比较【个人总结】
- 黑马程序员--07.集合框架--并发访问异常理解:一个单线程程序的多线程运行思想【个人总结】