JAVA之旅(二十)—HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习

JAVA之旅(二十)—HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习


我们继续说一下集合框架

  • Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复

Set集合的功能和Collection是一致的

我们重点关注的是子类对象

我们来聊聊

一.HashSet

HashSet底层结构是哈希表

什么是HashSet?

package com.lgl.hellojava;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        Demo d1 = new Demo();
        Demo d2 = new Demo();

        sop(d1);
        sop(d2);
    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }

}

class Demo {

}

我们这样输出的结果就是哈希值

当然,我们是来介绍HashSet的,我们演示一下

package com.lgl.hellojava;

import java.util.HashSet;
import java.util.Iterator;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        HashSet h = new HashSet();
        h.add("hello 01");
        h.add("hello 02");
        h.add("hello 03");
        h.add("hello 04");

        // set取出只有一种办法,迭代器
        Iterator iterator = h.iterator();
        while (iterator.hasNext()) {
            sop(iterator.next());
        }

    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }

}

是不是很类似,但是输出,你们仔细看了

输出是无序的,我们还有一个现象,就是直接输出

sop(h.add("lgl"));
sop(h.add("lgl"));

相同的

因为他不能重复

二.自定义存储对象

我们可以存数据,那肯定可以自定义存储数据咯?

package com.lgl.hellojava;

import java.util.HashSet;
import java.util.Iterator;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        HashSet h = new HashSet();
        h.add(new Person("lgl1", 18));
        h.add(new Person("lgl2", 19));
        h.add(new Person("lgl3", 20));
        h.add(new Person("lgl4", 21));

        // set取出只有一种办法,迭代器
        Iterator iterator = h.iterator();
        while (iterator.hasNext()) {
            Person p = (Person) iterator.next();
            sop(p.getName() + ":" + p.getAge());
        }

    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }

}

/**
 * 存储对象
 *
 * @author LGL
 *
 */
class Person {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

这样就可以定下来了

  • HashSet是如何保证元素的唯一性呢?
    • 是通过元素的两个方法,hasCode和equals来完成的
    • 如果元素的hasCode相同。才会去判断equals是否为true
    • 如果元素的hasCode不同。不会调用equals

这里要注意一点的就是,对于判断元素是否存在的话,以及删除的操作,依赖的方法就是元素的hasCode和equals

三.TreeSet

hashSet说完,我们再来看一下TreeSet,我们用小例子来说明

package com.lgl.hellojava;

import java.util.Iterator;
import java.util.TreeSet;

import org.omg.PortableInterceptor.Interceptor;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        TreeSet s = new TreeSet();
        s.add("abc");
        s.add("acd");
        s.add("age");
        s.add("abf");

        Iterator iterator = s.iterator();

        while (iterator.hasNext()) {
            sop(iterator.next());
        }
    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }
}

我们仔细看他的输出

他会排序,那我们就知道TreeSet的特性了

  • 可以对Set集合中的元素进行排序

如果你用自定义对象去村粗的话,你会发现他可以存一个对象,但是不能存储多个对象,为什么?因为他会强制进行排序,如果是对象的话,他没法排序,是不行的

对了我们没有讲TreeSet的数据结构呢,他的数据结构是二叉树,这是一个比较难的概念了

四.二叉树

二叉树其实通俗一点,就是树形图数据,比如

就是比较,一直分支,很大的节约了计算方式,我们比较,大的话,开一个分支,小的话,再开一个分支,就这样一直比较!

那TreeSet保证元素唯一性的是compareTo方法return 0;

  • TreeSet排序的第一种方式,让元素自身具备比较性,元素需要实现Comparable 接口,覆盖compareTo方法,这种也称为元素的自然顺序!

五.实现Comparator方式排序

当元素不具备比较性时,或者具备的元素的比较性不是所需要的,这时就需要让集合自身具备比较性,那就是在集合一初始化时就有了比较方式.这么说有点绕啊,我们还是用代码来说明吧,原理都是二叉树

package com.lgl.hellojava;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        /**
         * 当元素自身不具备比较性或者具备的比较性不是所需要的,这时需要让容器自生具备比较性,定义一个比较器,
         * 将比较器对象作为参数传递给TreeSet集合的构造函数
         */
        TreeSet s = new TreeSet(new MyCompare());
        s.add(new Student("lgl1", 22));
        s.add(new Student("lgl2", 26));
        s.add(new Student("lgl3", 10));
        s.add(new Student("lgl4", 19));

        Iterator iterator = s.iterator();
        while (iterator.hasNext()) {
            Student student = (Student) iterator.next();
            sop(student.getName() + ":" + student.getAge());
        }

    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }
}

class Student {
    private String name;
    private int age;

    public 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;
        if (this.age > s.age) {
            return 1;
        } else if (this.age == s.age) {
            return this.name.compareTo(s.name);
        }
        return -1;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

// 定义比较器
class MyCompare implements Comparator {

    public int compare(Object o1, Object o2) {
        Student s1 = (Student) o1;
        Student s2 = (Student) o2;

        return s1.getName().compareTo(s2.getName());
    }

}

六.TreeSet小练习

我们到这里,就用一个小练习来结束吧,毕竟在后面就需要讲泛型了,我们的需求就是按照字符串長度排序

package com.lgl.hellojava;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

//公共的   类   类名
public class HelloJJAVA {
    public static void main(String[] args) {
        /**
         * 按照字符串長度排序
         */
        TreeSet s = new TreeSet(new StringLengthComparator());
        s.add("ffffffff");
        s.add("fffff");
        s.add("ff");
        s.add("ffffff");

        Iterator iterator = s.iterator();
        while (iterator.hasNext()) {
            sop(iterator.next());
        }

    }

    // 输出
    public static void sop(Object obj) {
        System.out.println(obj);

    }
}

// 定义比较性
class StringLengthComparator implements Comparator {

    @Override
    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;

    }

}

这样就OK了,输出的结果

这样就O了,好的,但是我们重复元素也会被干掉的,这时候我们就要处理了

    @Override
    public int compare(Object o1, Object o2) {

        String s1 = (String) o1;
        String s2 = (String) o2;

        int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
        if (num == 0) {
            return s1.compareTo(s2);
        }
        return -num;

    }

到这里,就基本上都搞定了,我们的博文到这里也结束了,如果有机会

可以加群讨论:555974449

时间: 2024-10-26 09:45:39

JAVA之旅(二十)—HashSet,自定义存储对象,TreeSet,二叉树,实现Comparator方式排序,TreeSet小练习的相关文章

JAVA之旅(十二)——Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口

JAVA之旅(十二)--Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口 开始挑战一些难度了,线程和I/O方面的操作了,继续坚持 一.Thread 如何在自定义的代码中,自定义一个线程呢? 我们查看API文档,我们要启动一个线程,先实现一个子类, package com.lgl.hellojava; public class MyThread extends Thread { @Override public void run()

JAVA之旅(十八)——基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用

JAVA之旅(十八)--基本数据类型的对象包装类,集合框架,数据结构,Collection,ArrayList,迭代器Iterator,List的使用 JAVA把完事万物都定义为对象,而我们想使用数据类型也是可以引用的 一.基本数据类型的对象包装类 左为基本数据类型,又为引用数据类型 byte Byte int Integer long Long boolean Booleab float Float double Double char Character 我们拿Integer来举例子 //整

JAVA之旅(十)——异常的概述,Try-Catch,异常声明Throws,多异常处理,自定义异常,Throw和Throws的区别

JAVA之旅(十)--异常的概述,Try-Catch,异常声明Throws,多异常处理,自定义异常,Throw和Throws的区别 不知不觉,JAVA之旅这个系列已经更新到第十篇了,感觉如梦如幻,时间过得很快,转眼一个月就这样过去了,我们不多说,继续我们的JAVA之旅 一.异常的概述 异常算是程序中一个比较重要的环节了,我们首先来看一下异常的体系,我们举一个小例子,定义一个除法方法 //公共的 类 类名 public class HelloJJAVA { // 公共的 静态 无返回值 main方

JAVA之旅(十六)——String类,String常用方法,获取,判断,转换,替换,切割,子串,大小写转换,去除空格,比较

JAVA之旅(十六)--String类,String常用方法,获取,判断,转换,替换,切割,子串,大小写转换,去除空格,比较 过节耽误了几天,我们继续JAVA之旅 一.String概述 String时我们很常用的数据类型,他也是一个类的使用 我们来看 package com.lgl.hellojava; //公共的 类 类名 public class HelloJJAVA { public static void main(String[] args) { /** * String */ /**

JAVA之旅(十五)——多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止

JAVA之旅(十五)--多线程的生产者和消费者,停止线程,守护线程,线程的优先级,setPriority设置优先级,yield临时停止 我们接着多线程讲 一.生产者和消费者 什么是生产者和消费者?我们解释过来应该是生产一个,消费一个,的意思,具体我们通过例子来说 package com.lgl.hellojava; //公共的 类 类名 public class HelloJJAVA { public static void main(String[] args) { /** * 生产者和消费者

JAVA之旅(十四)——静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制

JAVA之旅(十四)--静态同步函数的锁是class对象,多线程的单例设计模式,死锁,线程中的通讯以及通讯所带来的安全隐患,等待唤醒机制 JAVA之旅,一路有你,加油! 一.静态同步函数的锁是class对象 我们在上节验证了同步函数的锁是this,但是对于静态同步函数,你又知道多少呢? 我们做一个这样的小实验,我们给show方法加上static关键字去修饰 private static synchronized void show() { if (tick > 0) { try { Thread

Java设计模式(二十)----状态模式

状态模式 一.概述 二.结构 三.具体案例 四.认识状态模式 一.概述 定义:允许一个对象的内部状态改变时改变它的行为.对象看起来似乎修改了它的类. 本质:根据状态来分离和选择行为. 状态:对象实例的属性值. 行为:对象的功能,大多对应到方法上. 状态模式的功能:分离状态的行为,通过维护状态的变化,来调用不同装态对应的不同功能. 状态和行为是相关联的,可以描述为:状态决定行为. 状态模式和策略模式的结构师完全一样的,但它们的目的.实现.本质却完全不一样.状态模式的行为是平行的,不可相互替换的:而

Java基础知识二十九

Java 基础语法 一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如,一条狗是一个对象,它的状态有:颜色.名字.品种:行为有:摇尾巴.叫.吃等. 类:类是一个模板,它描述一类对象的行为和状态. 方法:方法就是行为,一个类可以有很多方法.逻辑运算.数据修改以及所有动作都是在方法中完成的. 实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定. 如果你想学

Java设计模式(二十二)----调停者模式

调停者模式 定义:调停者模式包装了一系列对象相互作用的方式,使得这些对象不必相互明显引用.从而使它们可以较松散地耦合.当这些对象中的某些对象之间的相互作用发生改变时,不会立即影响到其他的一些对象之间的相互作用.从而保证这些相互作用可以彼此独立地变化. 为什么需要调停者 如下图所示,这个示意图中有大量的对象,这些对象既会影响别的对象,又会被别的对象所影响,因此常常叫做同事(Colleague)对象.这些同事对象通 过彼此的相互作用形成系统的行为.从图中可以看出,几乎每一个对象都需要与其他的对象发生