您的位置:首页 > 其它

day15TreeSet,二叉树原理,比较器,泛型,自定义泛型

2013-05-23 11:13 302 查看
/*
TreeSet,二叉树原理,比较器,泛型,自定义泛型
*/

/*
|--Set:元素是无序的(存入和取出的顺序不一致),元素不可重复
|--HashSet:底层数据结构是哈希表。线程是非同步的。
是如何保证元素的唯一性的呢?(依据)
判断是通过元素的两个方法,先判断hashCode,如果相同,再判断equals来完成
如果元素Hashcode一样,才会判断equals是否为真
如果元素的Hashcode不同,不会调用equals.

注意,对于判断元素是否存在,以及删除等操作,依赖hashCode和equals方法来完成

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

二叉树存:大的在右下,小的在左下。
取值:先取小的,再取大的

排序技巧:当compareTo()总是返回1:正序。就是和存入顺序一样了。
返回-1,逆序。

TreeSet排序的第一种方式。让元素自身具备可比性
元素需要实现Comparable接口,覆盖compareTo方法
这种方式就是元素的自然顺序。

TreeSet的第二种排序方式。比较器
当元素自身不具备比较性时,或者具备的比较性不是所需要的
这时就需要让集合具备比较性。
定义一个类,实现Comparator接口,覆盖compare方法。
在集合初始化时,传入这个类的对象,就有了比较方式。
TreeSet ts = new TreeSet(new Mycompare());

Set集合的功能和Collect是一致的,
哈希表存对象。
先比较哈希值,如果相同,再比较对象equals。

练习需求:往TreeSet集合中存储自定义对象学生
想按照学生的年龄进行排序。

comparable compareTo , comparator compare
记住。排序时,当主要条件相同时,按照次要条件再排序。
*/
import java.util.*;

class  TreeSetDemo
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet();
ts.add(new Student("lisi02",22));//为什么存一个没事?存二个就出错?
//向Tree里面存对象,是要排序的,必须要有比较性,类的自然顺序。
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
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());
//System.out.println(it.next());
}

}
}

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)//覆盖接口方法
{
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 0;当年龄相同,再判断姓名。主副条件
{
return this.name.compareTo(s.name);//String也实现了此接口
}
return -1;
}

public String getName()
{
return name;
}

public int getAge()
{
return age;
}
}

import java.util.*;
/*
TreeSet的第二种排序方式。
当元素自身不具备比较性时,或者具备的比较性不是所需要的
这时就需要让集合自身具备比较性。
构造函数:在集合初始化时,就有了比较方式。

当二种都存在时,以比较器为主(好)。
比较器类:定义一个类,实现Comparator接口,覆盖compare方法。

我们发现,当我们定义一个学生类时,要有自己的hashCode,equals,compareTo方法,
当然还有toString方法。
*/

class  TreeSetDemo2
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new Mycompare());//以比较器为主
ts.add(new Student("lisi02",22));//没有比较器时,为什么存一个没事?存二个就出错?
//向Tree里面存对象,是要排序的,必须要有比较性,类的自然顺序。
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi01",40));//如果年龄相同,那么存不进去?Set是无序,元素不重复。

Iterator it = ts.iterator();
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
//System.out.println(it.next());
}
}
}

class Mycompare implements Comparator//比较器方式
{
public int compare(Object o1,Object o2)
{
Student s1 = (Student)o1;
Student s2 = (Student)o2;

int num =  s1.getName().compareTo(s2.getName());//按名字排序
if (num==0)//名字相同,再比较年龄
{
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}

return num;
}
}

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)
{
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 0;当年龄相同,再判断姓名。
{
return this.name.compareTo(s.name);//String 也实现了此接口
}
return -1;
}

public String getName()
{
return name;
}

public int getAge()
{
return age;
}
}

/*
练习:按照字符串长度排序

字符串本身具备比较性。但这个排序方式不是我们想要的
*/
import java.util.*;
class  TreeSetTest
{
public static void main(String[] args)
{
TreeSet ts = new TreeSet(new  StrLenComparator());
ts.add("abcd");
ts.add("cc");
ts.add("cba");
ts.add("z");
ts.add("hahaha");

Iterator it = ts.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
}

class StrLenComparator implements Comparator
{
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 0;

return -1;
*///为什么不相接用int比较?那不是对象,没有compareTo方法。
int num = new  Integer(s.length()).compareTo(new Integer(s2.length()));
if(num ==0)
{
return s1.compareTo(s2);
}
return num;
}
}

/*
泛型:jdk1.5版本以后出现的新特性,用于解决安全问题,
是一个类型安全机制。

好处:
1.把运行时出现的ClassCastException问题放到编译时.
让程序员解决问题,减少安全问题。

2.避免了强制转换的麻烦。

泛型格式:通过<>来定义要操作的引用数据类型

在使用java提供的对象时,什么时候写泛型呢?
在集合框架中很常见。
只要有<>就要定义泛型。
其实<>就是用来接受类型的。

当使用集合时,将集合中要存储的数据类型作为参数
传递到<>中就可以了。

类似数组一样。
装入时候明确要装入的<类型>。
ArrayList<String> al = new ArrayList<String>();
*/
class  GenericDemo
{
public static void main(String[] args)
{
ArrayList<String> al = new ArrayList<String>();
al.add("abc01");
al.add("abc0001");
al.add("abc014");
//al.add(4);问题所在。编译可以通过,运行出问题。
Iterator<String> it = al.iterator();
while(it.hasNext())
{
String s = it.next();//2避免了强制转换的麻烦。
System.out.println(s+":"+s.length());
}
}
}

//------下面是泛型一个例子。字符串长度排序。
import java.util.*;

class  GenericDemo2
{
public static void main(String[] args)
{
TreeSet<String> ts = new TreeSet<String>(new StrLenComparator());
ts.add("abcd");
ts.add("cc");
ts.add("cba");
ts.add("z");
ts.add("hahaha");

Iterator<String> it = ts.iterator();
while (it.hasNext())
{
System.out.println(it.next());
}
}
}

class StrLenComparator implements Comparator<String>
{
public int compare(String o1,String o2)//当类上加上<String>,此处不是Object了
{
int num = new Integer(o1.length()).compareTo(new  Integer(o2.length()));

if(num == 0)
{
return o1.compareTo(o2);
}
return num;
}
}

/*
自定义泛型类
我们能不能在自己定义的类中使用泛型来完成程序设计呢?
什么时候使用泛型类:
当类中要操作的引用数据类型不确定的时候,
早期定义Object来完成扩展。现在定义泛型来完成扩展。

只能是引用的,基本数据类型定义不了,
基本数据类型比如说char类型,
本来就是char了,就不能再用泛型规范了。

泛型方法:
泛型除了可以定义在类上,还可以定义在方法上。
泛型类定义的泛型在整个类中有效。如果被方法使用,
那么如果泛型类的对象已经明确操作的具体类型后,所
有要操作的类型就已经固定了。

class Tool
{
private Worker w;
public void setWorker(Worker w)
{
this.w = w;
}

public Worker getWorker()
{
return w;
}
}第一次
*/
/*
class Worker
{

}

class Tool
{
private Object obj;
public void setObject(Object obj)
{
this.obj = obj;
}

public Object getObject()
{
return obj;
}
}第二次

class Student
{

}
class GenericDemo3
{
public static void main(String[] args)
{
Tool t = new Tool();
t.setObject(new Student());
//不小心传了学生,编译通过,运行出错。
//这时自己明确传什么,拿什么。
Worker w = (Worker)t.getObject();
}
}
*/
//以上是早期做法,是可以的,得有强转。
//对象都是后过来的,泛型之前用object
//避免一个类要一个工具类操作

//我要操作对象,什么类型不确定。
//由对方来指定要操作什么类型的对象

class Utils<QQ>//泛型类
{
private QQ q;
public void setObject(QQ q)
{
this.q = q;
}
public QQ getObject()
{
return q;
}
}

class Student
{

}
class GenericDemo3
{
public static void main(String[] args)
{
/*
Tool t = new Tool();
t.setObject(new Student());
//不小心传了学生,编译通过,运行出错。
//这时自己明确传什么,拿什么。
Worker w = (Worker)t.getObject();
*/
Utils<Worker> u = new Utils<Worker>();//泛型
u.setObject(new Worker());
Worker w = u.getObject();//可以不用强转,传入其他的就失败。

}
}

/*泛型方法*/
class  GenericDemo4
{
public static void main(String[] args)
{
/*
Demo<Integer> d = new Demo<Integer>();
d.show(new Integer(4));
d.print(9);
定义在类上时
*/
Demo d = new Demo();
d.show("haah");
d.show(new Integer(4));
d.print("heihei");
}
}
class Demo
{
public <T> void show(T t)//<T>定义在方法上,<T>只在方法中有效
{
System.out.println("show:"+t);
}
public <Q> void print(Q q)//这里写<T>也可以
{
System.out.println("print:"+q);
}
}

/*
class Demo<T>//泛型定义在类上
{
public void show(T t)
{
System.out.println("show:"+t);
}
public void print(T t)
{
System.out.println("print:"+t);
}
//以前要明确操作类型,现在可以这样写,传什么都行。

//泛型类的局限性:当new一个对象时,已经定义类型了。
//Demo<Integer> d = new Demo<Integer>();
//泛型类定义的泛型在整个类中有效。如果被方法使用,
//那么如果泛型类的对象已经明确操作的具体类型后,所
//有要操作的类型就已经固定了。

//为了让不同方法可以操作不同类型,而且类型还不确定。
//那么可以将泛型定义在方法上。public <T> void print(Q q)

泛型类和方法可以同时定义。
}
*/
/*特殊之处:
当类有静态方法时,不可以访问在类上定义的泛型。
如果静态方法操作的引用数据类型不确定,
可以将泛型定义在方法上。因为静态方法先加载。
public static <W> void method(W w)
{//注意泛型方法书写格式,<W>在void前,返回类型前。
System.out.println("method" + w);
}
*/
/*
泛型接口:如果类不能确定自己要传什么,也可以定义泛型
*/
interface Inter<T>
{
void show(T t);
}
/*
class InterImpl implements Inter<String>
{
public void show(String s)
{
System.out.println("show"+s);
}
}//第一种
*/
//后来我自己也不知道自己要传什么类型,
//子类也不知道,由调用者来指定
class InterImpl<T> implements Inter<T>
{
public void show(T t)
{
System.out.println("show:"+t);
}
}
class GenericDemo5
{
public static void main(String args[])
{
//InterImpl i = new InterImpl();
//i.show("haha");
InterImpl<Integer> i = new InterImpl<Integer>();
i.show(4);
//由调用者自己指定Integer
}
}

/*import java.util.*;
<T>具体类型。<?>占位符,通配符。
<?>不明确类型,iterator时不能打印it.next().length().
ArrayList<Person> al = new ArrayList<Student>();
这是不允许的。左右二边要一致。泛型没有继承关系。

泛型的限定:
1.?extends E:可以接收E类型或者E的子类型。上限
2.?super E:可以接收E类型或者E的父类型。下限。
*/
class  GenericDemo6
{

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: