(集合) TreeSet

目录

 

TreeSet:能够对元素按照某种规则进行排序。

TreeSet   add()方法的JDK源码:

TreeSet集合的特点:排序和唯一

自然排序:Comparable

例一:(存储字符串并遍历)

例二:存储自定义对象

比较器排序:comparator

例一:存储自定义对象

需求一:获取10个1至20的随机数,要求随机数不能重复。

需求二:学生总分从高到低输出到控制台


TreeSet:能够对元素按照某种规则进行排序。

 * 排序有两种方式
 * A:自然排序//默认TreeMap的构造器方法
 * B:比较器排序//comparator
 * 
 * TreeSet集合的特点:排序和唯一

TreeSet   add()方法的JDK源码:

interface Collection {...}

interface Set extends Collection {...}

interface NavigableMap {

}

class TreeMap implements NavigableMap {
//TreeMap存储根据红黑树,其实是二叉树 
//该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator //进行排序,具体取决于使用的构造方法。 

        
     private final Comparator<? super K> comparator;
     //走无参构造
     public TreeMap() {
        comparator = null;
    }
    //走带参构造
    //构造一个新的、空的树映射,该映射根据给定比较器进行排序。
    public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;
    }


	 public V put(K key, V value) {//key是要插入进来的值
        Entry<K,V> t = root;//树的存储需要根,前边造的是根
        if (t == null) {
            compare(key, key); // type (and possibly null) check

            root = new Entry<>(key, value, null);
            size = 1;
            modCount++;
            return null;
        }
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
        //Comparator:强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有序set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序,里边比较的方法是compare()
        Comparator<? super K> cpr = comparator;
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        //自然排序
        else {
            if (key == null)
                throw new NullPointerException();
            //此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 //compareTo 方法被称为它的自然比较方法。
            Comparable<? super K> k = (Comparable<? super K>) key;//此处是自然排序和比较器排序的区别
            do {
                parent = t;
                cmp = k.compareTo(t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;
        modCount++;
        return null;
    }
}

class TreeSet implements Set {
    //默认构造方法构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
    //NavigableMap其实是一个接口,如果调用其实调用的是他的实现类TreeMap
	private transient NavigableMap<E,Object> m;
	
	public TreeSet() {
    //创建实例要调用TreeMap方法的put方法,,接口实例化需要new一个子类对象
		 this(new TreeMap<E,Object>());
	}
	public boolean add(E e) {
    //put方法是treemap方法里的
        return m.put(e, PRESENT)==null;
    }
}

通过观察TreeSet的add()方法,我们知道最终要看TreeMap的put()方法。

真正的比较是依赖于元素的compareTo()方法,而这个方法是定义在 Comparable里面的。
所以,要想重写该方法,就必须是先 Comparable接口。这个接口表示的就是自然排序。

TreeSet集合的特点:排序和唯一

自然排序:Comparable

例一:(存储字符串并遍历)

由于Integer类实现了Comparable接口并重写了compareTo()方法,所以满足了集合的排序和唯一

		TreeSet<Integer> ts = new TreeSet<Integer>();

		// 创建元素并添加
		// 20,18,23,22,17,24,19,18,24
		ts.add(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 (Integer i : ts) {
			System.out.println(i);
		}

例二:存储自定义对象

必须实现Comparable并覆盖里边的compareTo()方法

例一:存储学生对象

pojo对象Student类加入以下方法:(0:相等;-1:小于;1:大于)

	@Override
	public int compareTo(Student s) {
		// return 0;
		// return 1;
		// return -1;

		// 这里返回什么,其实应该根据我的排序规则来做
		// 按照年龄排序,主要条件
		int num = this.age - s.age;
		// 次要条件
		// 年龄相同的时候,还得去看姓名是否也相同
		// 如果年龄和姓名都相同,才是同一个元素
		int num2 = num == 0 ? this.name.compareTo(s.name) : num;
		return num2;
	}

测试类:

		TreeSet<Student> ts =new TreeSet<Student>();
        Student s1 = new Student("jay", 27);
        Student s2 = new Student("jay", 29);
        Student s4 = new Student("jay", 27);
        Student s5 = new Student("tom", 29);
        ts.add(s1);
        ts.add(s2);
        ts.add(s4);
        ts.add(s5);

        for (Student s : ts) {
            System.out.println(s.getUsername() + "---" + s.getPassword());
        }
        //去除了用户名和密码都相同的对象
        //jay---27
        //jay---29
        //tom---29

需求一:根据姓名长度来排序

同理,只需要在pojo对象Student类加入以下方法:

	@Override
	public int compareTo(Student s) {
		// 主要条件 姓名的长度
		int num = this.name.length() - s.name.length();
		// 姓名的长度相同,不代表姓名的内容相同
		int num2 = num == 0 ? this.name.compareTo(s.name) : num;
		// 姓名的长度和内容相同,不代表年龄相同,所以还得继续判断年龄
		int num3 = num2 == 0 ? this.age - s.age : num2;
		return num3;
	}

比较器排序:comparator

* TreeSet集合保证元素排序和唯一性的原理
 * 唯一性:是根据比较的返回是否是0来决定。
 * 排序:
 *         A:自然排序(元素具备比较性)
 *             让元素所属的类实现自然排序接口 Comparable
 *         B:比较器排序(集合具备比较性)
 *             让集合的构造方法接收一个比较器接口的子类对象 Comparator

TreeSet的排序方式有构造方法决定

例一:存储自定义对象

Student类不实现Comparator接口,而是定义一个MyComparator类来实现接口,在创建TreeSet树时,把MyComparator对象传递进去。

MyComparator.java

    @Override
	public int compare(Student s1, Student s2) {
		// int num = this.name.length() - s.name.length();
		// this -- s1
		// s -- s2
		// 姓名长度
		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;
	}

测试类:

第一种写法:

        TreeSet<Student> ts = new TreeSet<Student>(); //自然排序
        //public TreeSet(Comparator comparator) //比较器排序
        TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());
        Student s1 = new Student("jay", 27);
        Student s2 = new Student("jay", 29);
        Student s4 = new Student("jay", 27);
        Student s5 = new Student("tom", 29);
        ts.add(s1);
        ts.add(s2);
        ts.add(s4);
        ts.add(s5);
        for (Student s : ts) {
			System.out.println(s.getName() + "---" + s.getAge());
		}

第二种:使用匿名内部类

// 如果一个方法的参数是接口,那么真正要的是接口的实现类的对象
// 而匿名内部类就可以实现这个东西
// 此时TreeMap源码中德 private final Comparator<? super K> comparator;不为空,在源码中接下去判断走的是比较器排序
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				// 姓名长度
				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("jay", 27);
        Student s2 = new Student("jay", 29);
        Student s4 = new Student("jay", 27);
        Student s5 = new Student("tom", 29);
        ts.add(s1);
        ts.add(s2);
        ts.add(s4);
        ts.add(s5);
        for (Student s : ts) {
			System.out.println(s.getName() + "---" + s.getAge());
		}

需求一:获取10个1至20的随机数,要求随机数不能重复。

 /* 分析:
 * 		A:创建随机数对象
 * 		B:创建一个HashSet集合
 * 		C:判断集合的长度是不是小于10
 * 			是:就创建一个随机数添加
 * 			否:不搭理它
 * 		D:遍历HashSet集合
 */
public class HashSetDemo {
	public static void main(String[] args) {
		// 创建随机数对象
		Random r = new Random();

		// 创建一个Set集合
		HashSet<Integer> ts = new HashSet<Integer>();

		// 判断集合的长度是不是小于10
		while (ts.size() < 10) {
			int num = r.nextInt(20) + 1;
			ts.add(num);
		}

		// 遍历Set集合
		for (Integer i : ts) {
			System.out.println(i);
		}
	}
}

需求二:学生总分从高到低输出到控制台

 /* 分析:
 * 		A:定义学生类
 * 		B:创建一个TreeSet集合
 * 		C:总分从高到底如何实现呢?		
 * 		D:键盘录入5个学生信息
 * 		E:遍历TreeSet集合
 */
public class TreeSetDemo {
	public static void main(String[] args) {
		// 创建一个TreeSet集合
		TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
			@Override
			public int compare(Student s1, Student s2) {
				// 总分从高到低
				int num = s2.getSum() - s1.getSum();
				// 总分相同的不一定语文相同
				int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
				// 总分相同的不一定数序相同
				int num3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
				// 总分相同的不一定英语相同
				int num4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;
				// 姓名还不一定相同呢
				int num5 = num4 == 0 ? s1.getName().compareTo(s2.getName())
						: num4;
				return num5;
			}
		});

		System.out.println("学生信息录入开始");
		// 键盘录入5个学生信息
		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 chineseString = sc.nextLine();
			System.out.println("请输入第" + x + "个学生的数学成绩:");
			String mathString = sc.nextLine();
			System.out.println("请输入第" + x + "个学生的英语成绩:");
			String englishString = sc.nextLine();

			// 把数据封装到学生对象中
			Student s = new Student();
			s.setName(name);
			s.setChinese(Integer.parseInt(chineseString));
			s.setMath(Integer.parseInt(mathString));
			s.setEnglish(Integer.parseInt(englishString));

			// 把学生对象添加到集合
			ts.add(s);
		}
		System.out.println("学生信息录入完毕");

		System.out.println("学习信息从高到低排序如下:");
		System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");
		// 遍历集合
		for (Student s : ts) {
			System.out.println(s.getName() + "\t" + s.getChinese() + "\t"
					+ s.getMath() + "\t" + s.getEnglish());
		}
	}
}

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值