Java笔记第十五课(TreeSet集合)

来源:互联网 发布:求生之路2mac视角不动 编辑:程序博客网 时间:2024/06/06 21:06

Set集合

 Set接口:Set集合继承自Collection集合

      Set:底层数据结构是一个哈希表,能保证元素是唯一的,元素不重复!  它通过它的子实现了HashSet集合去实例化,HashSet集合底层是HashMap集合的实例!  

 例. 需求:Set集合存储字符串元素并遍历

public class SetDemo {public static void main(String[] args) {//创建Set集合对象Set<String> set = new HashSet<String>() ;//添加元素set.add("hello");set.add("java") ;set.add("java") ;set.add("world") ;set.add("world") ;set.add("world") ;//增强for遍历for(String s :set){System.out.println(s);}}}


List集合和Set集合的区别?


    Set:元素是唯一的,无序性(存储和取出不一致)

    List:元素可以重复,有序性(存储和取出一致)

Set集合的子实现类:

1)HashSet:

实现Set接口,依靠Hashtable,他不保证迭代的顺序,特别的是,它不能保证数据保持不变,随着时间的推移。这个集合可以包含null值。存储结构实际为HashMap


HashSet集合的add()方法,底层是依赖于双列集合HashMap<K,V>的put(K key,V value)来实现的
   put(K key,V value):
    底层又依赖于HashCode()和equals()方法,传递添加元素的时候,首先判断的是
  每一个元素对应的HashCode值是否一样,如果HashCode值一样,还比较他们的equals()方法,由于现在集合存储的是String类型,String类型本身重写
  了equals()方法,所以,默认比较的是内容是否相同,如果内容相同,这里最终返回的就是第一次存储的那个元素,由这两个方法保证元素唯一性!

例:使用HashSet集合存储自定义对象并遍历

import java.util.HashSet;public class HashSetDemo {public static void main(String[] args) {//创建一个HashSet集合对象HashSet<Student> hs = new HashSet<Student>() ;//创建学生对象Student s1 = new Student("高圆圆", 27) ;Student s2 = new Student("张三", 25) ;Student s3 = new Student("唐嫣", 26) ;Student s4 = new Student("邓超", 29) ;Student s5 = new Student("胡歌", 23) ;Student s6 = new Student("高圆圆", 27) ;//给集合中添加学生对象hs.add(s1) ;hs.add(s2) ;hs.add(s3) ;hs.add(s4) ;hs.add(s5) ;hs.add(s6) ;//增强for遍历for(Student s : hs){System.out.println(s.getName()+"---"+s.getAge());}/** * "高圆圆---27" 重复出现是因为现在是自定义对象:在当前自定义对象的类中没有重写两个方法                 * hashCode和equals()方法;HashSet底层是依赖于这两个实现来保证元素的唯一性!                 *  * */}}

HashSet的子类LinkedHashSet集合:
         由哈希表保证元素的唯一性
         由链接列表来保证元素的有序性!

        具有可预知迭代顺序的Set接口的哈希表和链接列表实现。此实现与HashSet的不同之处在于,后者维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序可为插入顺序或是访问顺序。

public class LinkedHashSetDemo {public static void main(String[] args) {//创建LinkedHashSet集合对象LinkedHashSet<String> link = new LinkedHashSet<String>();//给集合中添加元素link.add("hello") ;link.add("world") ;link.add("world") ;link.add("Java") ;link.add("Java") ;link.add("JavaWeb") ;link.add("JavaWeb") ;//遍历集合for(String s: link){System.out.println(s);//元素唯一并且有序}}}


2) TreeSet集合

先了解一下红黑树

红黑树是一种自平衡的二叉查找树 ,那么二叉查找树(BST)具备什么特性呢?


1.左子树上所有结点的值均小于或等于它的根结点的值。
2.右子树上所有结点的值均大于或等于它的根结点的值。
3.左、右子树也分别为二叉排序树。




这种方式是二分查找的思想,当需要查找10这个元素时,查找的次数就是树的高度,但是二叉查找树也存在缺陷,比如


所以红黑树应运而生关于红黑树的规则:

1.节点是红色或黑色。
2.根节点是黑色。
3.每个叶子节点都是黑色的空节点(NIL节点)。
4 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

下图中这棵树,就是一颗典型的红黑树:



红黑树可以通过变色 ,旋转来调整被打破的规则

TreeSet集合底层是依赖于TreeMap的实例,而TreeMap<K,V>是依赖于红黑树结构实现的

分两种:

   自然排序:
   比较器排序
  这种排序的使用取决于开发者是用什么样的构造方法

public class TreeSetDemo {public static void main(String[] args){//throw new IOException();//创建TreeSet集合对象//构造方法://public TreeSet():无参构造:根据其元素的自然顺序进行排序//publict TreeSet(Comparaptr<E> com)TreeSet<Integer> ts = new TreeSet<Integer>();////添加元素//20,18,23,22,17,24,19,18,24ts.add(20);// Integer i = Integer.valueOf(20) ;ts.add(18) ;ts.add(23) ;ts.add(22) ;ts.add(17) ;ts.add(24) ;ts.add(19) ;ts.add(18) ;ts.add(24) ;//遍历这些元素//增强for遍历for(Integer i : ts){System.out.print(i+ " ");//17 18 19 20 22 23 24 :唯一并且排序:自然排序(升序排序)}}}

TreeSet集合存储自定义对象并遍历

对于TreeSet集合存储自定义对象必须实现一个接口:compareable接口


Student类中实现了compareable接口,重写了comapreTo()方法,里面的逻辑是一个排序条件:

public class TreeSetDemo2 {public static void main(String[] args) {//创建TreeSet集合对象TreeSet<Student> ts = new TreeSet<Student>() ;////创建学生对象Student s1 = new Student("linqingxia", 28) ;Student s2 = new Student("fengqingy", 28) ;Student s3 = new Student("gaoyuanyuan", 27) ;Student s4 = new Student("liushishi", 26) ;Student s5 = new Student("wanglihong", 29) ;Student s6 = new Student("zhangguorong", 30) ;Student s7 = new Student("zhangguorong", 30) ;ts.add(s1);ts.add(s2);ts.add(s3);ts.add(s4);ts.add(s5);ts.add(s6);ts.add(s7);//遍历for(Student s : ts){System.out.println(s.getName()+"---"+s.getAge());}}}

需求:按照学生姓名长度从小到大进行排序
 
  元素唯一性:取决返回值是否为0
  要使用TreeSet集合的比较器排序:
   依赖于构造方法:
   public TreeSet(Comparator<E> comparator)
  
   两种方式实现比较器排序:
  Comparator接口作为形式参数进行传递,需要该接口的子实现类对象

方式1:自定义一个类,类实现Comparator接口,作为子实现类
方式2:可以使用接口的匿名内部类来实现(开发中,由于减少代码书写量,不需要自定义接口的子实现类,直接这种格式! )

public class TreeSetDemo {public static void main(String[] args) {//创建TreeSet集合使用比较器进行给元素进行排序//public TreeSet(Comparator<E> comparator):有参构造//使用接口的匿名内部类来实现/** * 格式 * new 接口名或者类名(){ * 重写方法() ; * }  *///TreeSet<Student> ts = new TreeSet<Student>(new MyComparator()) ;TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {@Overridepublic int compare(Student s1, Student s2) {//return 0;int num = s1.getName().length() - s2.getName().length() ;//次要条件:姓名长度一样,还要比较姓名的内容是否一样int num2 = num==0 ? s1.getName().compareTo(s2.getName()): num ;//姓名长度和内容都一样,还需比较两个人的年龄是否一样int num3 = num2 ==0 ? s1.getAge() - s2.getAge() : num2 ;return num3 ;}}) ;//创建学生对象Student s1 = new Student("gaoyuanyan", 27) ;Student s2 = new Student("liushishi", 22);Student s3 = new Student("fengqingy", 23) ;Student s4 = new Student("wuqilong", 35) ;Student s5 = new Student("gaoyuanyuan",27) ;Student s6 = new Student("zhangguorong",29) ;Student s7 = new Student("gaoyuanyuan",26) ;//添加元素ts.add(s1) ;ts.add(s2) ;ts.add(s3) ;ts.add(s4) ;ts.add(s5) ;ts.add(s6) ;ts.add(s7) ;//增强for遍历for(Student s : ts){System.out.println(s.getName()+"----"+s.getAge());}}}
练习:键盘录入五个农药英雄比较他们的各自特点及总体性能
public class TreeSetTest {public static void main(String[] args) {//创建TreeSet集合TreeSet<Hreo> ts = new TreeSet<Hreo>(new Comparator< Hreo>() {@Overridepublic int compare(Hreo h1, Hreo h2) {//条件int num = h2.getSum() - h1.getSum();int num2 = num == 0?h1.getLive()-h2.getLive():num;int num3 = num == 0?h1.getAttack()-h2.getAttack():num2;int num4 = num == 0?h1.getSkill()-h2.getSkill():num3;int num5 = num == 0?h2.getDifficult()-h1.getDifficult():num4;return num5;}});System.out.println("录入英雄信息开始:");//创建键盘录入并使用String类型接受for(int x =1;x <= 5;x++) {Scanner sc = new Scanner(System.in);System.out.println("请输入第"+x+"个英雄的姓名:");String name = sc.nextLine();System.out.println("请输入第"+x+"个英雄的生存值:");String liveString = sc.nextLine();System.out.println("请输入第"+x+"个英雄的技能值:");String skillString = sc.nextLine();System.out.println("请输入第"+x+"个英雄的难度值:");String difficultString = sc.nextLine();System.out.println("请输入第"+x+"个英雄的攻击值:");String attackString = sc.nextLine();//创建英雄对象Hreo  h = new Hreo();//把英雄信息传进去h.setName(name);//将String类型转为int类型h.setLive(Integer.parseInt(liveString));h.setSkill(Integer.parseInt(skillString));h.setDifficult(Integer.parseInt(difficultString));h.setAttack(Integer.parseInt(attackString));ts.add(h);System.out.println("英雄信息录入完毕!");System.out.println("英雄性能从高到低排列如下:");System.out.println("姓名\t生存\t技能\t难度\t攻击");//增强for遍历for(Hreo h1:ts) {System.out.println(h1.getName() + "\t" + h1.getLive() + "\t" + h1.getSkill() + "\t" + h1.getDifficult() + "\t" + h1.getAttack());}}}}

获取10个1-20之间的随机数,要求不能重复

public class Test {public static void main(String[] args) {//1)创建一个随机数生成器Random r = new Random();//2)创建ArrayList集合,类型IntegerArrayList<Integer> array = new ArrayList<Integer>() ;//3)定义统计遍历int count = 0 ;//4)循环判断while(count <10){//通过随机数生成器获取:1-20之间的随机数public int nextInt(int n):生成随机数的范围:[0,n)int number = r.nextInt(20) +1;//有随机数了,还需要判断集合中是否包含这些随机数if(!array.contains(number)){//如果不包含,才添加到集合中array.add(number) ;count ++ ;}}//遍历集合:增强forfor(Integer i : array){System.out.println(i);}}}


原创粉丝点击