1.Collection集合
1.1数组和集合的区别【理解】
-
相同点
都是容器,可以存储多个数据
-
不同点
-
数组的长度是不可变的,集合的长度是可变的
-
数组可以存基本数据类型和引用数据类型
集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类
-
1.2集合类体系结构【理解】
1.3Collection 集合概述和使用【应用】
-
Collection集合概述
- 是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素
- JDK 不提供此接口的任何直接实现.它提供更具体的子接口(如Set和List)实现
-
创建Collection集合的对象
- 多态的方式
- 具体的实现类ArrayList
-
Collection集合常用方法
方法名 说明 boolean add(E e) 添加元素 boolean remove(Object o) 从集合中移除指定的元素 boolean removeIf(Object o) 根据条件进行移除 void clear() 清空集合中的元素 boolean contains(Object o) 判断集合中是否存在指定的元素 boolean isEmpty() 判断集合是否为空 int size() 集合的长度,也就是集合中元素的个数
public class CollectionMethod {
public static void main(String[] args) {
Collection<String> c = new ArrayList<>();//多态写法
//public boolean add(E e)把给定的对象添加到当前集合中
c.add("hello");
c.add("world");
c.add("java");
System.out.println(c.size());//public int size返回当前集合中元素的个数
System.out.println(c);
System.out.println(c.contains("hello"));//public boolean contains(Object o)判断当前集合中是否包含给定的对象
c.remove("hello");//public boolean remove(Object o)把给定的对象在当前集合中删除
System.out.println(c);
System.out.println(c.contains("hello"));//public boolean contains(Object o)判断当前集合中是否包含给定的对象
c.clear();//清除集合中所有的元素
System.out.println(c);
System.out.println(c.isEmpty());// public boolean isEmpty()判断当前集合是否为空
Object[] arr = c.toArray();//public Object[] toArray();把集合转换为数组
//把一个集合的全部数据倒入到另一个集合中去
Collection<String> c1 = new ArrayList<>();
c1.add("hello");
c1.add("world");
c1.add("java");
Collection<String> c2 = new ArrayList<>();
c2.add("hello");
c2.add("world");
c2.add("java");
c1.addAll(c2);
System.out.println(c1);
}
}
1.4Collection集合的遍历【应用】
-
迭代器介绍
- 迭代器,集合的专用遍历方式
- Iterator iterator(): 返回此集合中元素的迭代器,通过集合对象的iterator()方法得到
-
Iterator中的常用方法
boolean hasNext(): 判断当前位置是否有元素可以被取出
E next(): 获取当前位置的元素,将迭代器对象移向下一个索引位置 -
Collection集合的遍历1
public class IteratorDemo1 { public static void main(String[] args) { //创建集合对象 Collection<String> c = new ArrayList<>(); //添加元素 c.add("hello"); c.add("world"); c.add("java"); c.add("javaee"); //Iterator<E> iterator():返回此集合中元素的迭代器,通过集合的iterator()方法得到 Iterator<String> it = c.iterator(); //用while循环改进元素的判断和获取 while (it.hasNext()) { String s = it.next(); System.out.println(s); } } }
-
迭代器中删除的方法
void remove(): 删除迭代器对象当前指向的元素
public class IteratorDemo2 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("b"); list.add("c"); list.add("d"); Iterator<String> it = list.iterator(); while(it.hasNext()){ String s = it.next(); if("b".equals(s)){ //指向谁,那么此时就删除谁. it.remove(); } } System.out.println(list); } }
1.5增强for循环【应用】
-
介绍
- 它是JDK5之后出现的,其内部原理是一个Iterator迭代器
- 实现Iterable接口的类才可以使用迭代器和增强for
- 简化数组和Collection集合的遍历
-
格式
for(集合/数组中元素的数据类型 变量名 : 集合/数组名) {
// 已经将当前遍历到的元素封装到变量中了,直接使用变量即可
}
-
代码
public class MyCollectonDemo1 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.add("e"); list.add("f"); //1,数据类型一定是集合或者数组中元素的类型 //2,str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素 //3,list就是要遍历的集合或者数组 for(String str : list){ System.out.println(str); } } }
1.6 Lambda表达式
得益于JDK 8 开始的新技术Lambda表达式,提供了一种更简单、更直接的方式来遍历集合
方法:
方法名称 | 说明 |
---|---|
default void forEach(Consumer<? super T> action) | 结合lambda遍历集合 |
//default void forEach(Consumer<? super T> action) 结合lambda表达式进行遍历
collection.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
});
collection.forEach(s -> System.out.println(s));
public class CollectionBianLi {
public static void main(String[] args) {
Collection<String> collection = new ArrayList<>();
collection.add("张三");
collection.add("李四");
collection.add("马刺");
//default void forEach(Consumer<? super T> action) 结合lambda表达式进行遍历
// collection.forEach(new Consumer<String>() {
// @Override
// public void accept(String s) {
// System.out.println(s);
// }
// });
collection.forEach(s -> System.out.println(s));
}
}
2.List集合
2.1List集合的概述和特点【记忆】
- List集合的概述
- 有序集合,这里的有序指的是存取顺序
- 用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素
- 与Set集合不同,列表通常允许重复的元素
- List集合的特点
- 存取有序
- 可以重复
- 有索引
2.2List集合的特有方法【应用】
方法名 | 描述 |
---|---|
void add(int index,E element) | 在此集合中的指定位置插入指定的元素 |
E remove(int index) | 删除指定索引处的元素,返回被删除的元素 |
E set(int index,E element) | 修改指定索引处的元素,返回被修改的元素 |
E get(int index) | 返回指定索引处的元素 |
package List;
import java.util.ArrayList;
import java.util.List;
public class ListMethod {
public static void main(String[] args) {
//1.创建一个ArrayList集合对象(有序、可重复、有索引)
List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
System.out.println(list);
//2.public void add(int index ,E element):在某个索引位置插入元素
list.add(2,"紫霞仙子");
System.out.println(list);
//3.public E remove(int index):根据索引删除元素,返回被删除元素
System.out.println(list.remove(2));
System.out.println(list);
//4.public E get (int index):根据索引删除元素,返回被删除元素
System.out.println(list.get(2));
//5.public E set(int index,E element):修改索引位置处的元素,修改成功后。会返回原来的数据
System.out.println(list.set(2,"紫霞仙子"));
System.out.println(list);
}
}
2.3List集合遍历
package List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
public class ListBianLi {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("hello");
list.add("world");
list.add("java");
//for循环
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
System.out.println(s);
}
System.out.println("-------------------");
//迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println("-------------------");
//增强for循环
for(String s : list){
System.out.println(s);
}
System.out.println("-------------------");
//JDK 1.8开始之后的Lambda表达式
list.forEach(s -> System.out.println(s) );
}
}
3.数据结构
3.1数据结构之栈和队列【记忆】
-
栈结构
先进后出
-
队列结构
先进先出
3.2数据结构之数组和链表【记忆】
-
数组结构
查询快、增删慢
-
队列结构
查询慢、增删快
4.List集合的实现类
4.1List集合子类的特点【记忆】
-
ArrayList集合
底层是数组结构实现,查询快、增删慢
-
LinkedList集合
底层是链表结构实现,查询慢、增删快
4.2LinkedList集合的特有功能【应用】
-
特有方法
方法名 说明 public void addFirst(E e) 在该列表开头插入指定的元素 public void addLast(E e) 将指定的元素追加到此列表的末尾 public E getFirst() 返回此列表中的第一个元素 public E getLast() 返回此列表中的最后一个元素 public E removeFirst() 从此列表中删除并返回第一个元素 public E removeLast() 从此列表中删除并返回最后一个元素
package List;
import java.util.LinkedList;
import java.util.List;
public class LinkedListMrthod {
public static void main(String[] args) {
LinkedList<String> list = new LinkedList<>();
list.add("hello");
list.add("world");
list.add("java");
System.out.println(list);
//1.public void addFirst(E e) 在该列表开头插入指定的元素
list.addFirst("紫霞");
System.out.println(list);
//2.public void addLast(E e) 将指定的元素追加到此列表的末尾
list.addLast("至尊宝");
System.out.println(list);
//3.返回此列表中的对一个元素 public E getFirst()
System.out.println(list.getFirst());
//4.返回此列表中最后一个元素public E getLast()
System.out.println(list.getLast());
//5.从此列表中删除并返回第一个元素public E removeFirst()
System.out.println(list.removeFirst());
System.out.println(list);
//6.从列表中删除并返回最后一个元素 public E removeLast()
System.out.println(list.removeLast());
System.out.println(list);
}
}
5.泛型
5.1泛型概述【理解】
-
泛型的介绍
泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制
-
泛型的好处
- 把运行时期的问题提前到了编译期间
- 避免了强制类型转换
-
泛型的定义格式
- <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如:
- <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>
5.2泛型类【应用】
-
定义格式
修饰符 class 类名<类型> { }
-
示例代码
-
泛型类
public class Generic<T> { private T t; public T getT() { return t; } public void setT(T t) { this.t = t; } }
-
测试类
public class GenericDemo1 { public static void main(String[] args) { Generic<String> g1 = new Generic<String>(); g1.setT("杨幂"); System.out.println(g1.getT()); Generic<Integer> g2 = new Generic<Integer>(); g2.setT(30); System.out.println(g2.getT()); Generic<Boolean> g3 = new Generic<Boolean>(); g3.setT(true); System.out.println(g3.getT()); } }
-
5.3泛型方法【应用】
-
定义格式
修饰符 <类型> 返回值类型 方法名(类型 变量名) { }
-
示例代码
-
带有泛型方法的类
public class Generic { public <T> void show(T t) { System.out.println(t); } }
-
测试类
public class GenericDemo2 { public static void main(String[] args) { Generic g = new Generic(); g.show("柳岩"); g.show(30); g.show(true); g.show(12.34); } }
-
5.4泛型接口【应用】
-
定义格式
修饰符 interface 接口名<类型> { }
-
示例代码
-
泛型接口
public interface Generic<T> { void show(T t); }
-
泛型接口实现类1
定义实现类时,定义和接口相同泛型,创建实现类对象时明确泛型的具体类型
public class GenericImpl1<T> implements Generic<T> { @Override public void show(T t) { System.out.println(t); } }
-
泛型接口实现类2
定义实现类时,直接明确泛型的具体类型
public class GenericImpl2 implements Generic<Integer>{ @Override public void show(Integer t) { System.out.println(t); } }
-
测试类
public class GenericDemo3 { public static void main(String[] args) { GenericImpl1<String> g1 = new GenericImpl<String>(); g1.show("林青霞"); GenericImpl1<Integer> g2 = new GenericImpl<Integer>(); g2.show(30); GenericImpl2 g3 = new GenericImpl2(); g3.show(10); } }
-
5.5类型通配符
-
类型通配符: <?>
- ArrayList<?>: 表示元素类型未知的ArrayList,它的元素可以匹配任何的类型
- 但是并不能把元素添加到ArrayList中了,获取出来的也是父类类型
-
类型通配符上限: <? extends 类型>
- ArrayListList <? extends Number>: 它表示的类型是Number或者其子类型
-
类型通配符下限: <? super 类型>
- ArrayListList <? super Number>: 它表示的类型是Number或者其父类型
-
泛型通配符的使用
public class GenericDemo4 { public static void main(String[] args) { ArrayList<Integer> list1 = new ArrayList<>(); ArrayList<String> list2 = new ArrayList<>(); ArrayList<Number> list3 = new ArrayList<>(); ArrayList<Object> list4 = new ArrayList<>(); method(list1); method(list2); method(list3); method(list4); getElement1(list1); getElement1(list2);//报错 getElement1(list3); getElement1(list4);//报错 getElement2(list1);//报错 getElement2(list2);//报错 getElement2(list3); getElement2(list4); } // 泛型通配符: 此时的泛型?,可以是任意类型 public static void method(ArrayList<?> list){} // 泛型的上限: 此时的泛型?,必须是Number类型或者Number类型的子类 public static void getElement1(ArrayList<? extends Number> list){} // 泛型的下限: 此时的泛型?,必须是Number类型或者Number类型的父类 public static void getElement2(ArrayList<? super Number> list){} }
6.Set集合
6.1Set集合概述和特点
不可以存储重复元素
没有索引,不能使用普通for循环遍历
6.2Set集合的使用
存储字符串并遍历
public class MySet1 {
public static void main(String[] args) {
//创建集合对象
Set<String> set = new TreeSet<>();
//添加元素
set.add("ccc");
set.add("aaa");
set.add("aaa");
set.add("bbb");
// for (int i = 0; i < set.size(); i++) {
// //Set集合是没有索引的,所以不能使用通过索引获取元素的方法
// }
//遍历集合
Iterator<String> it = set.iterator();
while (it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("-----------------------------------");
for (String s : set) {
System.out.println(s);
}
}
}
6.3TreeSet集合
6.3.1TreeSet集合概述和特点
- 不可以存储重复元素
- 没有索引
- 可以将元素按照规则进行排序
- TreeSet():根据其元素的自然排序进行排序
- TreeSet(Comparator comparator) :根据指定的比较器进行排序
6.3.2TreeSet集合基本使用
存储Integer类型的整数并遍历
public class TreeSetDemo01 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Integer> ts = new TreeSet<Integer>();
//添加元素
ts.add(10);
ts.add(40);
ts.add(30);
ts.add(50);
ts.add(20);
ts.add(30);
//遍历集合
for(Integer i : ts) {
System.out.println(i);
}
}
}
6.3.3自然排序Comparable的使用
-
案例需求
- 存储学生对象并遍历,创建TreeSet集合使用无参构造方法
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
-
实现步骤
-
使用空参构造创建TreeSet集合
- 用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
-
自定义的Student类实现Comparable接口
- 自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
-
重写接口中的compareTo方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
-
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
//按照对象的年龄进行排序
//主要判断条件: 按照年龄从小到大排序
int result = this.age - o.age;
//次要判断条件: 年龄相同时,按照姓名的字母顺序排序
result = result == 0 ? this.name.compareTo(o.getName()) : result;
return result;
}
}
public class MyTreeSet2 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<>();
//创建学生对象
Student s1 = new Student("zhangsan",28);
Student s2 = new Student("lisi",27);
Student s3 = new Student("wangwu",29);
Student s4 = new Student("zhaoliu",28);
Student s5 = new Student("qianqi",30);
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
//遍历集合
for (Student student : ts) {
System.out.println(student);
}
}
}
6.3.4比较器排序Comparator的使用
-
案例需求
- 存储老师对象并遍历,创建TreeSet集合使用带参构造方法
- 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
-
实现步骤
- 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
- 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
public class Teacher {
private String name;
private int age;
public Teacher() {
}
public Teacher(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class MyTreeSet4 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
//o1表示现在要存入的那个元素
//o2表示已经存入到集合中的元素
//主要条件
int result = o1.getAge() - o2.getAge();
//次要条件
result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
}
});
//创建老师对象
Teacher t1 = new Teacher("zhangsan",23);
Teacher t2 = new Teacher("lisi",22);
Teacher t3 = new Teacher("wangwu",24);
Teacher t4 = new Teacher("zhaoliu",24);
//把老师添加到集合
ts.add(t1);
ts.add(t2);
ts.add(t3);
ts.add(t4);
//遍历集合
for (Teacher teacher : ts) {
System.out.println(teacher);
}
}
}
6.3.5两种比较方式总结
- 两种比较方式小结
- 自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
- 比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
- 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
- 两种方式中关于返回值的规则
- 如果返回值为负数,表示当前存入的元素是较小值,存左边
- 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
- 如果返回值为正数,表示当前存入的元素是较大值,存右边
6.4HashSet集合
6.4.1HashSet集合概述和特点
- 底层数据结构是哈希表
- 存取无序
- 不可以存储重复元素
- 没有索引,不能使用普通for循环遍历
6.4.2HashSet集合的基本应用
存储字符串并遍历
public class HashSetDemo {
public static void main(String[] args) {
//创建集合对象
HashSet<String> set = new HashSet<String>();
//添加元素
set.add("hello");
set.add("world");
set.add("java");
//不包含重复元素的集合
set.add("world");
//遍历
for(String s : set) {
System.out.println(s);
}
}
}
6.4.3哈希值
-
哈希值简介
是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
-
如何获取哈希值
Object类中的public int hashCode():返回对象的哈希码值
-
哈希值的特点
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同
6.4.4哈希表结构【理解】
6.4.5HashSet集合存储学生对象并遍历【应用】
-
案例需求
- 创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合
- 要求:学生对象的成员变量值相同,我们就认为是同一个对象
-
代码实现
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
public class HashSetDemo02 {
public static void main(String[] args) {
//创建HashSet集合对象
HashSet<Student> hs = new HashSet<Student>();
//创建学生对象
Student s1 = new Student("林青霞", 30);
Student s2 = new Student("张曼玉", 35);
Student s3 = new Student("王祖贤", 33);
Student s4 = new Student("王祖贤", 33);
//把学生添加到集合
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
//遍历集合(增强for)
for (Student s : hs) {
System.out.println(s.getName() + "," + s.getAge());
}
}
}
- 总结
HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法
6.4.6 LinkedHashSet
LinkedHashSet是java集合框架的一个接口实现,它继承自HashSet并实现了Set接口。与普通的HashSet不同的是,LinkedHashSet维护了一个运行于所有条目的双向链表,这使得迭代顺序与插入顺序相同。
底层逻辑:
有序性:LinkedHashSet 保证了元素的插入顺序,即添加到集合中的元素会按照它们被添加的顺序进行存储和迭代。
不重复性:不允许集合中有重复的元素,如果尝试添加一个已经存在的元素,则该操作会被忽略。
效率:对于基本操作(如 add、remove 和 contains)的时间复杂度通常是 O(1),但在最坏的情况下可能是 O(n)。
使用LinkedHashSet去重:
如果需要从一个列表中去除重复元素,同时保持原有的顺序,可以使用 LinkedHashSet。以下是具体的步骤:
创建一个 LinkedHashSet:将列表作为构造函数的参数传递给 LinkedHashSet。
转换为列表:将 LinkedHashSet 转换回 List 类型。
package workTwo;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
public class workTwofive {
public static void main(String[] args) {
List<Integer> originalList = new ArrayList<>();
originalList.add(1);
originalList.add(2);
originalList.add(2);
originalList.add(3);
originalList.add(4);
originalList.add(4);
originalList.add(5);
System.out.println("原来的集合: " + originalList);
// 使用 LinkedHashSet 去除重复项
List<Integer> resultList = removeDuplicates(originalList);
System.out.println("去重后的集合: " + resultList);
}
private static List<Integer> removeDuplicates(List<Integer> originalList) {
// 使用 LinkedHashSet 来存储不重复的元素
LinkedHashSet<Integer> set = new LinkedHashSet<>(originalList);
// 将 LinkedHashSet 转换回 List
return new ArrayList<>(set);
}
}
7.数据结构
7.1二叉树
-
二叉树的特点
- 二叉树中,任意一个节点的度要小于等于2
- 节点: 在树结构中,每一个元素称之为节点
- 度: 每一个节点的子节点数量称之为度
- 二叉树中,任意一个节点的度要小于等于2
-
二叉树结构图
7.2二叉查找树
-
二叉查找树的特点
- 二叉查找树,又称二叉排序树或者二叉搜索树
- 每一个节点上最多有两个子节点
- 左子树上所有节点的值都小于根节点的值
- 右子树上所有节点的值都大于根节点的值
-
二叉查找树结构图
二叉查找树和二叉树对比结构图
二叉查找树添加节点规则
- 小的存左边
- 大的存右边
- 一样的不存
7.3平衡二叉树
-
平衡二叉树的特点
- 二叉树左右两个子树的高度差不超过1
- 任意节点的左右两个子树都是一颗平衡二叉树
-
平衡二叉树旋转
-
旋转触发时机
- 当添加一个节点之后,该树不再是一颗平衡二叉树
-
左旋
- 就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点
-
右旋
- 就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点
平衡二叉树和二叉查找树对比结构图
平衡二叉树旋转的四种情况
-
左左
-
左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡
-
如何旋转: 直接对整体进行右旋即可
-
左右
-
左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡
-
如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋
右右
-
右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡
-
如何旋转: 直接对整体进行左旋即可
右左
-
右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡
-
如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋
7.4红黑树
-
红黑树的特点
- 平衡二叉树
- 每一个节点可以是红或者黑
- 红黑树不是高度平衡的,它的平衡是通过"自己的红黑规则"进行实现的
-
红黑树的红黑规则有哪些
-
每一个节点或是红色的,或者是黑色的
-
根节点必须是黑色
-
如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的
-
如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连 的情况)
-
对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
-
红黑树添加节点的默认颜色
- 添加节点时,默认为红色,效率高
红黑树添加节点后如何保持红黑规则
- 根节点位置
- 直接变为黑色
- 非根节点位置
- 父节点为黑色
- 不需要任何操作,默认红色即可
- 父节点为红色
- 叔叔节点为红色
- 将"父节点"设为黑色,将"叔叔节点"设为黑色
- 将"祖父节点"设为红色
- 如果"祖父节点"为根节点,则将根节点再次变成黑色
- 叔叔节点为黑色
- 将"父节点"设为黑色
- 将"祖父节点"设为红色
- 以"祖父节点"为支点进行旋转
- 叔叔节点为红色
- 父节点为黑色
public class Student implements Comparable<Student> {
private String name;
private int chinese;
private int math;
private int english;
public Student() {
}
public Student(String name, int chinese, int math, int english) {
this.name = name;
this.chinese = chinese;
this.math = math;
this.english = english;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getEnglish() {
return english;
}
public void setEnglish(int english) {
this.english = english;
}
public int getSum() {
return this.chinese + this.math + this.english;
}
@Override
public int compareTo(Student o) {
// 主要条件: 按照总分进行排序
int result = o.getSum() - this.getSum();
// 次要条件: 如果总分一样,就按照语文成绩排序
result = result == 0 ? o.getChinese() - this.getChinese() : result;
// 如果语文成绩也一样,就按照数学成绩排序
result = result == 0 ? o.getMath() - this.getMath() : result;
// 如果总分一样,各科成绩也都一样,就按照姓名排序
result = result == 0 ? o.getName().compareTo(this.getName()) : result;
return result;
}
}
public class TreeSetDemo {
public static void main(String[] args) {
//创建TreeSet集合对象,通过比较器排序进行排序
TreeSet<Student> ts = new TreeSet<Student>();
//创建学生对象
Student s1 = new Student("jack", 98, 100, 95);
Student s2 = new Student("rose", 95, 95, 95);
Student s3 = new Student("sam", 100, 93, 98);
//把学生对象添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
//遍历集合
for (Student s : ts) {
System.out.println(s.getName() + "," + s.getChinese() + "," + s.getMath() + "," + s.getEnglish() + "," + s.getSum());
}
}
}
public void setEnglish(int english) {
this.english = english;
}
public int getSum() {
return this.chinese + this.math + this.english;
}
@Override
public int compareTo(Student o) {
// 主要条件: 按照总分进行排序
int result = o.getSum() - this.getSum();
// 次要条件: 如果总分一样,就按照语文成绩排序
result = result == 0 ? o.getChinese() - this.getChinese() : result;
// 如果语文成绩也一样,就按照数学成绩排序
result = result == 0 ? o.getMath() - this.getMath() : result;
// 如果总分一样,各科成绩也都一样,就按照姓名排序
result = result == 0 ? o.getName().compareTo(this.getName()) : result;
return result;
}
}
```java
public class TreeSetDemo {
public static void main(String[] args) {
//创建TreeSet集合对象,通过比较器排序进行排序
TreeSet<Student> ts = new TreeSet<Student>();
//创建学生对象
Student s1 = new Student("jack", 98, 100, 95);
Student s2 = new Student("rose", 95, 95, 95);
Student s3 = new Student("sam", 100, 93, 98);
//把学生对象添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
//遍历集合
for (Student s : ts) {
System.out.println(s.getName() + "," + s.getChinese() + "," + s.getMath() + "," + s.getEnglish() + "," + s.getSum());
}
}
}