人生苦短我学Java-13-泛型/Set集合/二叉树

本文详细介绍了Java中的泛型概念,包括泛型的作用、使用方式以及自定义泛型类和方法。同时,文章探讨了Set集合的特性,如无序、唯一性,并通过HashSet和TreeSet的实例展示了其实现。对于TreeSet,文章讲解了自定义类在TreeSet中的排序规则,包括Comparable接口和Comparator。最后,简要提及了数据结构中的树形结构,如二叉查找树和红黑树。
摘要由CSDN通过智能技术生成

一、泛型

1、什么是泛型?
参数化类型,就是指在定义泛型的时候,像在定义形参一样,在使用泛型的时候,需要传递数据类型。

泛型不能写基本数据类型,如int、布尔、byte,char等

泛型在编译后会擦除掉泛型的类型,实际上就可以理解编译后就没有了泛型。

写法:一般用第一种,这样就不会在idea中有警告了。

ArrayList<String> arr = new ArrayList<String>();
ArrayList<String> arr = new ArrayList<>();
ArrayList<String> arr= new ArrayList();

2、泛型的作用?
避免了强制类型转换
限制了集合中元素的数据类型

3、自定义泛型类

package com.ppl.object;
/*
com.ppl.object:学习项目
@user:广深-小龙
@date:2022/1/22 21:26
*/

import java.util.ArrayList;

public class Obj_fx {
    public static void main(String[] args) {
        // 泛型的使用,下面只能添加string类型
        ArrayList<String> arr = new ArrayList();
        arr.add("ppl");
        arr.add("123");
        for (Object o : arr) {
            System.out.print(o + " ");
        }

        // 自定义泛型类
        Fx<String> f = new Fx<>();
        f.test("只能是string");

        // 自定义泛型类+自定义泛型方法
        Fx<Integer> f1 = new Fx<>();
        f.test(123);

        // 自定义接口
        f.print("asd");
        new Fx().print("asd");
        new Fx().print(123);
        new Fx().print(true);
    }
}

// 自定义接口
interface If<E> {
    public abstract void print(E e);
}

// 自定义泛型类
class Fx<E> implements If<E> {
    // 自定义泛型方法
    public <E> void test(E e) {
        System.out.println(e);
    }

    // 自定义接口, 重写抽象方法
    public void print(E e) {
        System.out.println(e);
    }
}

 4、通配符

①List<?> arr2 = new ArrayList<>();

②泛型通配符 上限

<? extends 引用类型>

如Number类型,那么上限可以是数字相关:Integer、Float等子类包含自身,不能是父类如Objcet,或其它类型。

③泛型通配符 下限,和上限相反

<? super 引用类型>

如Number类型,那么上限可以是数字相关:父类如Objcet及包含自身,不能是Integer、Float等子类,或其它类型。

 

 二、Set集合

和Collection、List中成员方法一样,Set集合特点:

  • 无序的(存入与取出不一定一致顺序)
  • 无索引的
  • 元素唯一

1、HashSet上代码:

package com.ppl.object;
/*
com.ppl.object:学习项目
@user:广深-小龙
@date:2022/1/24 21:27
*/

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

public class Obj_Set {
    public static void main(String[] args) {
        Set set = new HashSet();
        set.add(123);
        set.add("123456");
        set.add(true);
        System.out.println(set);

        // 遍历,迭代器
        Iterator it = set.iterator();
        while (it.hasNext()) {
            System.out.println("迭代器" + it.next());
        }
        // 遍历,转数组
        Object[] obj = set.toArray();
        for (int i = 0; i < obj.length; i++) {
            System.out.println("转数组" + obj[i]);
        }
        // 遍历,增强for
        for (Object o : set) {
            System.out.println("增强for" + o);
        }
    }
}

2、TreeSet

树形结构中的:红黑树

特点:遍历和HashSet一致的

  • 无序的(存入与取出不一定一致顺序)
  • 无索引的
  • 元素唯一
  • 有排序(从小到到)
class MyTreeSet {
    public void test() {
        // TreeSet 会按照字典排序,有小到大排序。
        TreeSet t = new TreeSet();
        t.add("b");
        t.add("a");
        t.add("c");
//        t.add(123); 运行异常。因为字符串和integer不能混合排序

        TreeSet t1 = new TreeSet();
        t1.add(1);
        t1.add(3);
        t1.add(2);
        System.out.println(t);
        System.out.println(t1);
    }
}

自定义类,如果我们想要使用TreeSet来存储自定义对象的话,要满足两个条件之一才可以正常运行

  • 条件一:自然排序Comparable
  • 条件二:比较器Comparator
/*
add自定义类
如果我们想要使用TreeSet来存储自定义对象的话,要满足两个条件之一才可以正常运行
条件一:自然排序Comparable
如何实现自然排序?
    1.自定义类,实现Comparable接口
    2.重写抽象方法compareTo()
    3.在compareTo()方法中写比较规
        返回值为0:集合中的元素只有一个
        返回值为正数:集合中的元素是正序
        返回值为负数:集合中的元素是倒数
条件二:比较器Comparator
如何实现比较器?
    1.自定义类
    2.创建TreeSet集合对象,在构造方法中传递Comparator的对象
    3.重写compare()方法
    4.在compare()中写比较规则
        返回值为0:集合中的元素只有一个
        返回值为正数:集合中的元素是正序
        返回值为负数:集合中的元素是倒数
*/
class Person implements Comparable<Person> {


    // 1.自定义类,实现Comparable接口
    private String name;

    public Person() {
    }

    public Person(String name) {
        super();
        this.name = name;
        return;
    }

    // 2.重写抽象方法compareTo()
    @Override
    public int compareTo(Person o) {
//        return 0; // 只返回一个
//        return 1; // 正数 正序
        return -1;  // 负数 倒序    // 3.在compareTo()方法中写比较规
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}

// 条件二:自定义类
class Person1 {
    private String name;

    public Person1() {
    }

    public Person1(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Person1{" +
                "name='" + name + '\'' +
                '}';
    }
}

三、数据结构:树形

1、普通二叉树

  • 由根节点组成,只有一个根节点
  • 每个节点下最大只能有2个子节点
  • 查找速度慢,因为要全部遍历一遍

2、二叉查找树

升级版的普通二叉树

  • 由根节点组成,只有一个根节点
  • 每个节点下最大只能有2个子节点
  • 比当前值小排列左边,反之排列右边
  • 查找速度相对比普通二叉树快

 缺点:如果 元素为:1 2 3 4 5 6 7 8 9

一直排列在右边是不是也是很长?查找元素是不是也要遍历一遍?

肯定是的,只能说非此种情况下,查找元素相比普通二叉树速度要快。

3、平衡二叉树

在二叉查找树基础上,多了:层级高度差不超过1

如出现超出,那么会发生,左旋或右旋

4、红黑树

  • 红黑树的节点要么是黑色,要么是红色,根节点一定是黑色
  • 如果节点为红色,那么2个子节点都为黑色,不能连续两个红色的节点,如果没有子节点了,默认指向nil节点(叶子字节),叶子节点一定是黑色的
  • 任何一个节点到其叶子节点的这条件简单路径上黑色节点的个数是一样多的
  • 默认添加节点的颜色为红色

 默认节点为红色,只需要改变一个节点的颜色: 

 注意:

如果出现两个红色节点,需要判断:

父节点为红色,看父同级节点(叔叔节点)是红色还是黑色

      a:如果叔叔节点是红色:父节点由红变黑,叔叔节点由红变黑,爷爷由黑变红,如果爷爷节点是根节点,再由红变黑。

b:如果叔叔节点是黑色:父节点由红变黑,爷爷由黑变红,然后进行左旋或右旋,如果爷爷节点是根节点,再由红变黑。

由大到小排序:

class SetTest implements Comparable<SetTest> {
    private int age;

    public SetTest() {
    }

    public SetTest(int age) {
        super();
        this.age = age;
    }

    @Override
    public String toString() {
        return "SetTest{" +
                "age=" + age +
                '}';
    }

    @Override
    public int compareTo(SetTest o) {
        int i = o.age - this.age;
        /*
        i: 0  去重
        i: ≥1 右边排序
        i: ≤1 左边排序
        */
        return i;
    }
}

输出:[SetTest{age=5}, SetTest{age=3}, SetTest{age=1}]

欢迎来大家QQ交流群一起学习:482713805,博主微信+:gogsxl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姚二龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值