本文主要是介绍十三、集合进阶——单列集合 及 数据结构,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
单列集合 及 数据结构
- 13.1 集合体系结构
- 13.1.2 单列集合
- 1. Collection
- 2.Collection 的遍历方式
- 迭代器遍历
- 增强for遍历
- Lambda表达式遍历
- 3.List集合
- List集合的特有方法
- List集合的遍历方式
- 五种遍历方式对比
- 4.数据结构
- 1).栈
- 2).队列
- 3)数组
- 4)链表
- 小结
- 5)树
- 6)二叉查找树
- 7)平衡二叉树
- 平衡二叉树旋转机制——左旋
- 平衡二叉树旋转机制——右旋
- 平衡二叉树需要旋转的四种情况
- 8)红黑树
- 添加节点的规则
- 5.ArrayList集合
- 1.ArrayList集合底层原理
- 2.LinkedList集合
- 3.迭代器底层源码解析
- 6.泛型深入
- 1)泛型概述
- 2)泛型类
- 3)泛型方法
- 4)泛型接口
- 5)泛型的继承和通配符
- 总结
- 7.Set系列集合
- 1)HashSet
- 2)LinkedHashSet
- 3)TreeSet
- 8.单列集合使用场景
13.1 集合体系结构
13.1.2 单列集合
- List系列集合:添加的元素是有序、可重复、有索引。
- Set系列集合:添加的元素是无序、不重复、无索引。
1. Collection
Collection 是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
public static void main(String[] args) {/*注意点:* Collection 是一个接口,我们不能直接创建他的对象。* 所以,在学习它的方法时,只能创建他实现类的对象* 实现类:ArrayList** 目的:为了学习Collection接口里面的方法。*/Collection<String> coll = new ArrayList<>();//0.添加元素System.out.println("-------------0.添加元素-------------");/*细节1:如果要往List系列集合中添加数据,那么方法永远返回true,因为List系列的是允许元素重复的。* 细节2:如果要往Set系列集合中添加数据,如果当前要添加元素不存在,方法返回true,表示添加成功。* 如果当前要添加的元素已经存在,方法返回false,表示添加失败* 因为Set系列的集合不允许重复。*/coll.add("zhangsan");coll.add("aaa");coll.add("bbb");coll.add("ccc");System.out.println(coll); // [zhangsan, aaa, bbb, ccc]//1.清空System.out.println("-------------1.清空-------------");
// coll.clear();System.out.println(coll); // []//2.删除//细节1:因为Collection里面定义的是共性的方法,所以此时不能通过索引删除,只能通过元素的对象进行删除。//细节2:方法会有一个返回值,删除成功返回true,删除失败返回false。System.out.println("-------------2.删除-------------");coll.remove("aaa");System.out.println(coll); // [zhangsan, bbb, ccc]//3.判断元素是否包含/*细节:底层是依赖equals方法进行判断是否存在的。* 所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean类中,一定要重写equals方法*/System.out.println("-------------3.判断元素是否包含-------------");System.out.println(coll.contains("aaa")); //falseSystem.out.println(coll.contains("bbb")); // trueSystem.out.println("------------------------------------------");//4.判断是否为空System.out.println("-------------3.判断元素是否包含-------------");System.out.println(coll.isEmpty()); //falseSystem.out.println("------------------------------------------");//5.获取集合的长度int size = coll.size();System.out.println(size); // 3}
Contains方法 细节:
public static void main(String[] args) {//0.创建集合对象Collection<Student> coll = new ArrayList<>();//1.创建三个学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 25);Student s3 = new Student("wangwu", 26);//2.把学生对象添加到集合中coll.add(s1);coll.add(s2);coll.add(s3);//3.判断集合中某一个学生对象是否包含Student s4 = new Student("zhangsan", 23);/*因为contains方法在底层依赖equals方法判断对象是否一致的。如果存的是自定义对象,没有重写equals方法,那么默认使用Object类中的equals方法进行判断,而Object类中equals方法,依赖地址值进行判断。* 需求:如果同姓名和同年龄,就认为是同一个学生。所以,需要在自定义的Javabean类中,重写equals方法就可以了。*/System.out.println(coll.contains(s4));}
public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}
2.Collection 的遍历方式
迭代器遍历
迭代器不依赖索引
迭代器在Java中的类是 Iterrator ,迭代器是集合专用的遍历方式。
public static void main(String[] args) {//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("aaa");coll.add("bbb");coll.add("ccc");coll.add("ddd");//1.获取迭代器对象Iterator<String> it = coll.iterator();//2.利用循环不断的去获取集合中的每一个元素while (it.hasNext()) {//3.next方法的两件事情:获取元素并移动指针String str = it.next();System.out.println(str);}}
增强for遍历
public static void main(String[] args) {//增强for遍历//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("zhangsan");coll.add("lisi");coll.add("wangwu");//1.利用增强for遍历for (String s : coll) {System.out.println(s);}}
Lambda表达式遍历
public static void main(String[] args) {//Lambda 表达式遍历//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("zhangsan");coll.add("lisi");coll.add("wangwu");//利用匿名内部类的形式/*底层原理:* 其实也会自己遍历集合,依次得到每一个元素* 把得到的每一个元素,传递给下面的accept方法* s 依次表示集合中的每一个的对象 */coll.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});System.out.println("--------------------------");//1.Lambda表达式遍历coll.forEach(s -> System.out.println(s) );}
3.List集合
List集合的特有方法
public static void main(String[] args) {//0.创建一个集合List<String> list = new ArrayList<>();//1.添加元素list.add("aaa");list.add("bbb");list.add("ccc");//打印集合System.out.println(list); // [aaa, bbb, ccc]System.out.println("-------------------------");//2.在指定位置插入指定的元素list.add(2, "zhangsan");System.out.println(list); // [aaa, bbb, zhangsan, ccc]System.out.println("-------------------------");//3.删除指定索引处的元素,返回被删除的元素/*在调用方法的时候,如果方法出现了重载现象* 优先调用,实参跟形参类型一致的那个方法。*/String remove = list.remove(2);System.out.println(remove); // zhangsanSystem.out.println(list); // [aaa, bbb, ccc]System.out.println("-------------------------");//4.修改指定索引处的元素,返回被修改的元素list.set(0,"狗剩");System.out.println(list); // [狗剩, bbb, ccc]System.out.println("-------------------------");//5.返回指定索引处的元素String s = list.get(1);System.out.println(s); // bbb}
List集合的遍历方式
public static void main(String[] args) {//0.创建集合并添加元素List<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");//1.迭代器遍历Iterator<String> it = list.iterator();while (it.hasNext()) {String s = it.next();System.out.println(s);}System.out.println("------------------------");//2.增强forfor (String s : list) {System.out.println(s);}System.out.println("------------------------");//3.Lambda 表达式//匿名内部类list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});System.out.println("-------------------------");list.forEach(s -> System.out.println(s));System.out.println("------------------------");//4.普通for循环for (int i = 0; i < list.size(); i++) {String s = list.get(i);System.out.println(s);}System.out.println("-------------------------");//5.列表迭代器ListIterator<String> it2 = list.listIterator();while (it2.hasNext()){String s = it2.next();if ("bbb".equals(s)){it2.add("zhangsan");}System.out.println(s);}System.out.println(list); // [aaa, bbb, zhangsan, ccc]}
五种遍历方式对比
4.数据结构
- 数据结构:计算机存储、组织数据的方式
- 不同的业务场景要选择不同的数据结构。
- 是指数据之间是以什么方式排列在一起的。
- 数据结构是为了更加方便的管理和使用数据,需要结合具体的业务场景来进行选择。
- 一般情况下,精心选择的数据结构可以带来更高的运行或者存储效率。
- 每种数据结构长什么样子?
- 如何添加数据?
- 如何删除数据?
1).栈
栈的特点:后进先出,先进后出
2).队列
队列的特点:先进先出,后进后出
3)数组
- 查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
- 删除效率低:要将原始数据删除,同时后面每个数据前移。
- 添加效率极低:添加位置后的每个数据后移,再添加元素。
**数组是一种查询快,增删慢的模型。
4)链表
- 链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
- 链表查询慢,无论查询哪个数据都要从头开始找。
- 链表增删相对快。
小结
5)树
6)二叉查找树
前序遍历:
中序遍历:
后序遍历:
层序遍历:
7)平衡二叉树
平衡二叉树旋转机制——左旋
就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点
平衡二叉树旋转机制——右旋
就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点
平衡二叉树和二叉查找树对比结构图
平衡二叉树需要旋转的四种情况
-
左左
-
左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡
-
如何旋转: 直接对整体进行右旋即可
-
-
左右
- 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡
- 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋
-
右右
-
右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡
-
如何旋转: 直接对整体进行左旋即可
-
-
右左
-
右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡
-
如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋
-
8)红黑树
平衡二叉树:
- 高度平衡
- 当左右子树高度差超过1时,通过旋转保持平衡
红黑树:
- 是一个二叉查找树
- 但是不是高度平衡的
- 条件:特有的红黑规则
红黑规则:
- 每一个结点或是红色的,或是黑色的
- 根节点必须是黑色
- 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为 Nil ,这些 Nil 视为叶节点,每个叶节点(Nil)是黑色的
- 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
- 对每一个结点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
添加节点的规则
默认颜色:添加节点默认是红色的(效率高)
当默认是黑色时:
当默认是红色时:
红黑树添加节点后如何保持红黑规则
- 根节点位置
- 直接变为黑色
- 非根节点位置
- 父节点为黑色
- 不需要任何操作,默认红色即可
- 父节点为红色
- 叔叔节点为红色
- 将"父节点"设为黑色,将"叔叔节点"设为黑色
- 将"祖父节点"设为红色
- 如果"祖父节点"为根节点,则将根节点再次变成黑色
- 叔叔节点为黑色
- 将"父节点"设为黑色
- 将"祖父节点"设为红色
- 以"祖父节点"为支点进行旋转
- 叔叔节点为红色
- 父节点为黑色
举例:
跳过添加20、18、23
全部添加完成后:
再向其中添加 15 和 14
红黑树增删改查的性能都很好
5.ArrayList集合
1.ArrayList集合底层原理
2.LinkedList集合
3.迭代器底层源码解析
6.泛型深入
1)泛型概述
没有泛型的时候,集合如何存储数据?
public static void main(String[] args) {//没有泛型的时候,集合如何存储数据/*结论:* 如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型* 此时可以往集合添加任意的数据类型。* 带来一个坏处:我们在获取数据的时候,无法使用它的特有行为。*//*此时推出了泛型 ,可以在添加数据的时候就把类型进行统一。* 而且我们在获取数据的时候,也省的强转了,非常的方便。*///0.创建集合对象ArrayList<Object> list = new ArrayList<>();//1.添加数据list.add(123);list.add("abc");list.add(new Student("zhangsan", 123));//2.遍历集合获取集合中的每一个元素Iterator<Object> it = list.iterator();while (it.hasNext()){Object obj = it.next();//多态的弊端是不能访问子类的特有功能System.out.println(obj);}}
2)泛型类
package Generics;import java.util.Arrays;/** 当在编写一个类的时候,如果不确定类型,那么这个类型就可以定义为泛型类。* */
public class MyArrayList<E> {Object[] obj = new Object[10];int size;public boolean add(E e) {obj[size] = e;size++;return true;}public E get(int index) {return (E) obj[index];}@Overridepublic String toString() {return Arrays.toString(obj);}
}
public static void main(String[] args) {MyArrayList<String> list = new MyArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");System.out.println(list); // [aaa, bbb, ccc, null, null, null, null, null, null, null]MyArrayList<Integer> list2 = new MyArrayList<>();list2.add(123);list2.add(456);list2.add(789);System.out.println(list2); // [123, 456, 789, null, null, null, null, null, null, null]Integer i = list2.get(0);System.out.println(i); //123}
3)泛型方法
package Generics;import java.util.ArrayList;public class ListUtil {private ListUtil() {}//类中定义一个静态方法addAll,用来添加多个集合的元素。public static <E> void addAll(ArrayList<E> list, E e1, E e2, E e3, E e4) {list.add(e1);list.add(e2);list.add(e3);list.add(e4);}//添加元素个数未知public static <E> void addAll2(ArrayList<E> list, E...e) {for (E element : e) {list.add(element);}}
}
package Generics;import java.util.ArrayList;public class GenericsDemo3 {//定义一个工具类:ListUtil//类中定义一个静态方法addAll,用来添加多个集合的元素。public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();ListUtil.addAll(list, "aaa", "bbb", "ccc","ddd" );System.out.println(list);//[aaa, bbb, ccc, ddd]ArrayList<Integer> list1 = new ArrayList<>();ListUtil.addAll2(list1,1,2,3,4,5,6,7,8,9,3,6,4,2,5);System.out.println(list1);}
}
4)泛型接口
package Generics;import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;public class MyArrayList2 implements List<String> {@Overridepublic int size() {return 0;}@Overridepublic boolean isEmpty() {return false;}@Overridepublic boolean contains(Object o) {return false;}@Overridepublic Iterator<String> iterator() {return null;}@Overridepublic Object[] toArray() {return new Object[0];}@Overridepublic <T> T[] toArray(T[] a) {return null;}@Overridepublic boolean add(String s) {return false;}@Overridepublic boolean remove(Object o) {return false;}@Overridepublic boolean containsAll(Collection<?> c) {return false;}@Overridepublic boolean addAll(Collection<? extends String> c) {return false;}@Overridepublic boolean addAll(int index, Collection<? extends String> c) {return false;}@Overridepublic boolean removeAll(Collection<?> c) {return false;}@Overridepublic boolean retainAll(Collection<?> c) {return false;}@Overridepublic void clear() {}@Overridepublic String get(int index) {return null;}@Overridepublic String set(int index, String element) {return null;}@Overridepublic void add(int index, String element) {}@Overridepublic String remove(int index) {return null;}@Overridepublic int indexOf(Object o) {return 0;}@Overridepublic int lastIndexOf(Object o) {return 0;}@Overridepublic ListIterator<String> listIterator() {return null;}@Overridepublic ListIterator<String> listIterator(int index) {return null;}@Overridepublic List<String> subList(int fromIndex, int toIndex) {return null;}
}
public static void main(String[] args) {/*泛型接口的两种使用方式:* 1.实现类给出具体的类型* 2.实现类延续泛型,创建实现类对象时再确定类型 */MyArrayList2 list = new MyArrayList2();list.add("abc");//list.add(123); // java: 不兼容的类型: int无法转换为java.lang.String}
5)泛型的继承和通配符
- 泛型不具备继承性,但是数据具备继承性
- 泛型里面写的是什么类型,那么在方法中只能传递什么类型的数据。、
package Generics.Test;public abstract class Animal {/*属性:名字,年龄行为:吃东西*/private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public abstract void eat();public String toString() {return "Animal{name = " + name + ", age = " + age + "}";}
}
package Generics.Test;public abstract class Cat extends Animal{
}
package Generics.Test;public abstract class Dog extends Animal{
}
package Generics.Test;public class PersianCat extends Cat {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的波斯猫,正在吃小饼干");}
}
package Generics.Test;public class LiHuaCat extends Cat {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的狸花猫,正在吃鱼");}
}
package Generics.Test;public class HuskyDog extends Dog {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的哈士奇,正在吃骨头,边吃边拆家");}
}
package Generics.Test;public class TeddyDog extends Dog {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的泰迪,正在吃骨头,边吃边蹭");}
}
public static void main(String[] args) {/*需求:定义一个继承结构:动物| |猫 狗| | | |波斯猫 狸花猫 泰迪 哈士奇属性:名字,年龄行为:吃东西波斯猫方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干狸花猫方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼泰迪方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭哈士奇方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家测试类中定义一个方法用于饲养动物public static void keepPet(ArrayList<???> list){//遍历集合,调用动物的eat方法}要求1:该方法能养所有品种的猫,但是不能养狗要求2:该方法能养所有品种的狗,但是不能养猫要求3:该方法能养所有的动物,但是不能传递其他类型*/ArrayList<PersianCat> list1 = new ArrayList<>();ArrayList<LiHuaCat> list2 = new ArrayList<>();ArrayList<TeddyDog> list3 = new ArrayList<>();ArrayList<HuskyDog> list4 = new ArrayList<>();keepPet(list1);keepPet(list2);keepPet(list3);keepPet(list4);}//要求3:该方法能养所有的动物,但是不能传递其他类型public static void keepPet(ArrayList<? extends Animal> list){}//要求2:该方法能养所有品种的狗,但是不能养猫/*public static void keepPet(ArrayList<? extends Dog> list){}*///要求1:该方法能养所有品种的猫,但是不能养狗/*public static void keepPet(ArrayList<? extends Cat> list){}*/
总结
7.Set系列集合
- 不可以存储重复元素
- 没有索引,不能使用普通for循环遍历
- 无序:存取顺序不一致
- 不重复:可以去除重复
- 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素
Set 集合的实现类
- HashSet :无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:可排序、不重复、无索引
Set 接口中的方法上基本上与Collection的API一致
public static void main(String[] args) {/*练习 存储字符串并遍历* 利用Set系列的集合,添加字符串,并使用多种方式遍历* 0.迭代器* 1.增强for* 2.Lambda表达式*///0.创建Set集合的对线Set<String> s = new HashSet<>();//1.添加元素/*如果当前元素是第一次添加,那么可以添加成功,返回true* 如果当前元素是第二次添加,那么添加失败,返回false*/s.add("张三");s.add("李四");s.add("王五");//2.打印集合System.out.println(s); // [李四, 张三, 王五]//迭代器遍历Iterator<String> it = s.iterator();while (it.hasNext()) {String s1 = it.next();System.out.println(s1);}System.out.println("==========================");//增强for遍历for (String s2 : s) {System.out.println(s2);}System.out.println("=========================");//Lambda 表达式/*s.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});*/s.forEach(s3 -> System.out.println(s3));}
1)HashSet
HashSet 底层原理
- HashSet 集合底层采取哈希表存储数据
- 哈希表是一种对于增删改查数据性能都较好的结构
哈希表组成
- JDK8之前:数组+链表
- JDK8开始:数组+链表+红黑树
哈希值:对象的整数表现形式
哈希值:
- 根据hashCode方法计算出来的int类型的整数
- 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
- 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值
public static void main(String[] args) {//0.创建对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("zhangsan", 23);//1.如果没有重写hashCode方法,不同对象计算处的哈希值是不同的System.out.println(s1.hashCode()); // 990368553System.out.println(s2.hashCode()); // 1096979270//2.如果已经重写hashCode方法,不同的对象只要属性值相同,计算处的哈希值就是一样的System.out.println(s1.hashCode()); // -1461067292System.out.println(s2.hashCode()); // -1461067292//3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)System.out.println("abc".hashCode()); // 96354System.out.println("acD".hashCode()); // 96354}
public static void main(String[] args) {//0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 14);Student s3 = new Student("wangwu", 26);Student s4 = new Student("zhangsan", 23);//1.创建集合用来添加学生HashSet<Student> hs = new HashSet<>();//2.添加数据System.out.println(hs.add(s1)); //trueSystem.out.println(hs.add(s2)); //trueSystem.out.println(hs.add(s3)); //trueSystem.out.println(hs.add(s4)); //falseSystem.out.println(hs);}
package Set;import java.util.Objects;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;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
2)LinkedHashSet
public static void main(String[] args) {//0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 14);Student s3 = new Student("wangwu", 26);Student s4 = new Student("zhangsan", 23);//1.创建集合用来添加学生LinkedHashSet<Student> lhs = new LinkedHashSet<>();//2.添加数据System.out.println(lhs.add(s1)); //trueSystem.out.println(lhs.add(s2)); //trueSystem.out.println(lhs.add(s3)); //trueSystem.out.println(lhs.add(s4)); //falseSystem.out.println(lhs); //[Student{name='zhangsan', age=23}, Student{name='lisi', age=14}, Student{name='wangwu', age=26}]}
3)TreeSet
public static void main(String[] args) {/*需求:* 存储整数并进行排序 *///0.创建TreeSet集合对象TreeSet<Integer> ts = new TreeSet<>();//1.添加数据ts.add(4);ts.add(5);ts.add(2);ts.add(1);ts.add(3);//2.打印集合System.out.println(ts); // [1, 2, 3, 4, 5]//3.遍历//迭代器Iterator<Integer> it = ts.iterator();while (it.hasNext()) {Integer num = it.next();System.out.println(num);}System.out.println("=================");//加强forfor (Integer t : ts) {System.out.println(t);}System.out.println("======================");//Lambda表达式ts.forEach(num -> System.out.println(num));
public static void main(String[] args) {/*需求:* 创建TreeSet集合,并添加3个学生对象* 学生对象属性:* 姓名、年龄* 要求按照学生的年龄进行排序* 同年龄按照姓名字母排列(暂不考虑中文)* 同姓名,同年龄认为是同一个人** 方式一:* 默认的排序规则/自然排序* Student实现Comparable接口,重写里面的抽象方法,再指定比较规则** 方式二:* 比较器排序* 创建TreeSet对象的时候,传递比较器Comparator指定规则*///0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 24);Student s3 = new Student("wangwu", 25);//1.创建集合对象TreeSet<Student> ts = new TreeSet<>();//2.添加数据ts.add(s2);ts.add(s1);ts.add(s3);//3.打印数据System.out.println(ts);}
package Set;import java.util.Objects;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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {int res = this.getAge() - o.getAge();return res;}
}
public static void main(String[] args) {/** 需求:请自行选择比较器排序和自然排序两种方式:* 要求:存入四个字符串,c , ab , df , qwer* 按照长度排序,如果一样长则按照首字母排序*///0.创建集合/*o1:表示当前要添加的元素* o2:表示已经在红黑树存在的元素* 返回值:* 负数:认为要添加的元素是小的,存左边* 正数:认为要添加的元素是大的,存右边* 0:认为要添加的元素已经存在,舍弃*//*TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//按照长度排序int i = o1.length() - o2.length();//如果一样长则按照首字母排序i = i == 0 ? o1.compareTo(o2) : i;return i;}});*/TreeSet<String> ts = new TreeSet<>((o1, o2) -> {//按照长度排序int i = o1.length() - o2.length();//如果一样长则按照首字母排序i = i == 0 ? o1.compareTo(o2) : i;return i;});//添加数据ts.add("c");ts.add("ab");ts.add("df");ts.add("qwer");//打印System.out.println(ts); // [c, ab, df, qwer]}
package Set;public class Student2 implements Comparable<Student2> {/*属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)*/private String name;private int age;private int Chinese;private int Math;private int English;public Student2() {}public Student2(String name, int age, int Chinese, int Math, int English) {this.name = name;this.age = age;this.Chinese = Chinese;this.Math = Math;this.English = English;}/*** 获取** @return name*/public String getName() {return name;}/*** 设置** @param name*/public void setName(String name) {this.name = name;}/*** 获取** @return age*/public int getAge() {return age;}/*** 设置** @param age*/public void setAge(int age) {this.age = age;}/*** 获取** @return Chinese*/public int getChinese() {return Chinese;}/*** 设置** @param Chinese*/public void setChinese(int Chinese) {this.Chinese = Chinese;}/*** 获取** @return Math*/public int getMath() {return Math;}/*** 设置** @param Math*/public void setMath(int Math) {this.Math = Math;}/*** 获取** @return English*/public int getEnglish() {return English;}/*** 设置** @param English*/public void setEnglish(int English) {this.English = English;}public String toString() {return "Student2{name = " + name + ", age = " + age + ", Chinese = " + Chinese + ", Math = " + Math + ", English = " + English + "}";}/*按照总分从高到低输出到控制台* 如果总分一样,按照语文成绩排* 如果语文一样,按照数学成绩排* 如果数学成绩一样,按照英语成绩排* 如果英语成绩一样,按照年龄排* 如果年龄一样,按照姓名的字母顺序排* 如果都一样,认为是同一个学生,不存*/@Overridepublic int compareTo(Student2 o) {int sum1 = this.getChinese() + this.getMath() + this.getEnglish();int sum2 = o.getChinese() + o.getMath() + o.getEnglish();//比较总分int i = sum1 - sum2;//果总分一样,按照语文成绩排i = i == 0 ? this.getChinese() - o.getChinese() : i;//如果语文一样,按照数学成绩排i = i == 0 ? this.getMath() - o.getMath() : i;//如果数学成绩一样,按照英语成绩排(可以省略不写)i = i == 0 ? this.getEnglish() - o.getEnglish() : i;//如果英语成绩一样,按照年龄排i = i == 0 ? this.getAge() - o.getAge() : i;//如果年龄一样,按照姓名的字母顺序排i = i == 0 ? this.getName().compareTo(o.getName()) : i;return i;}
}
public static void main(String[] args) {/*需求:创建5个学生对象* 属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)* 按照总分从高到低输出到控制台* 如果总分一样,按照语文成绩排* 如果语文一样,按照数学成绩排* 如果数学成绩一样,按照英语成绩排* 如果英语成绩一样,按照年龄排* 如果年龄一样,按照姓名的字母顺序排* 如果都一样,认为是同一个学生,不存。*///0.创建5个学生对象Student2 s1 = new Student2("zhangsan", 23, 90, 99, 50);Student2 s2 = new Student2("lisi", 24, 90, 98, 50);Student2 s3 = new Student2("wangwu", 25, 95, 100, 30);Student2 s4 = new Student2("zhaoliu", 26, 60, 99, 70);Student2 s5 = new Student2("qianqi", 26, 70, 80, 70);//1.创建集合TreeSet<Student2> ts = new TreeSet<>();//2.添加数据ts.add(s1);ts.add(s2);ts.add(s3);ts.add(s4);ts.add(s5);//3.打印//System.out.println(ts);Iterator<Student2> it = ts.iterator();while (it.hasNext()) {Student2 info = it.next();int sum = info.getChinese() + info.getMath() + info.getEnglish();System.out.println(info + " 总分:" + sum);}/*Student2{name = qianqi, age = 26, Chinese = 70, Math = 80, English = 70} 总分:220Student2{name = wangwu, age = 25, Chinese = 95, Math = 100, English = 30} 总分:225Student2{name = zhaoliu, age = 26, Chinese = 60, Math = 99, English = 70} 总分:229Student2{name = lisi, age = 24, Chinese = 90, Math = 98, English = 50} 总分:238Student2{name = zhangsan, age = 23, Chinese = 90, Math = 99, English = 50} 总分:239*/}
8.单列集合使用场景
这篇关于十三、集合进阶——单列集合 及 数据结构的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!