Set集合---- HashSet集合、LinedHashSet集合、TreeSet集合
Set集合
1.Set集合:
無序(存儲和取出的順序)和唯一
Set接口:的三個子類 HashSet,LinkedHashSet, TreeSet
HashSet:底層資料結構是哈希表,元素無序(存的順序和取的順序不一緻),且不允許重複元素,可以存儲null元素,線程不安全,效率高!
package org.westos.demo1;
import java.util.HashSet;
public class MyTest2 {
public static void main(String[] args) {
HashSet<Integer> hashSet = new HashSet<>();
hashSet.add(100);
hashSet.add(100);
hashSet.add(100);
hashSet.add(200);
hashSet.add(300);
hashSet.add(400);
hashSet.add(500);
hashSet.add(500);
hashSet.add(500);
System.out.println(hashSet);
//String類和Integer類中都重寫了hashCode()和equals()方法,故列印的不是位址值
System.out.println("===============================");
for (Integer integer : hashSet) {
System.out.println(integer);
}
}
}
HashSet保證元素唯一性
HashSet 底層資料結構是哈希表. HashSet 不是線程安全的 集合元素可以是 null
哈希表:是一個元素為連結清單的數組,綜合了數組和連結清單的優點 (像新華字典一樣)
代碼:
public class MyTest {
public static void main(String[] args) {
HashSet<Student> hashSet = new HashSet<>();
hashSet.add(new Student("張三",23));
hashSet.add(new Student("張三", 23));
hashSet.add(new Student("李四", 24));
hashSet.add(new Student("王五", 25));
hashSet.add(new Student("趙六", 26));
hashSet.add(new Student("趙六", 26));
hashSet.add(new Student("田七", 27));
for (Student student : hashSet) {
System.out.println(student.getName()+"==="+student.getAge());
}
//當我們往hashset集合存儲對象的時候,會調用對象的hashCode方法,算出一個值,這個值就是确定這個對象放到表中的位置。
//那假如有兩個對象,算出的位置值是一樣的,就會調用equals()方法,去比較兩個對象的位址值是否一樣,如果不一樣那就存儲進去,形成連結清單結構
//為了減少碰撞,我們應該合理的去重寫hashCode方法,來減少碰撞(減少調用euquals方法的次數)盡量是元素在哈希表中橫向排列,減少連結清單的形成
}
}
當往hashset集合存儲對象的時候,會調用對象的hashCode方法,算出一個值,這個值就是确定這個對象放到表中的位置。
假如有兩個對象,算出的位置值是一樣的,就會調用equals()方法,去比較兩個對象的位址值是否一樣,如果不一樣那就存儲進去,形成連結清單結構
為了減少碰撞,我們應該合理的去重寫hashCode方法,來減少碰撞(減少調用euquals方法的次數)盡量是元素在哈希表中橫向排列,減少連結清單的形成。
結論:HashSet 保證元素唯一性是靠元素重寫hashCode()和equals()方法來保證的,如果不重寫則無法保證。
HashSet集合可以使用疊代器來周遊
代碼:
package org.westos.demo5;
import java.util.HashSet;
import java.util.Iterator;
public class MyTest1 {
public static void main(String[] args) {
HashSet<Integer> integers = new HashSet<>();
integers.add(100);
integers.add(200);
integers.add(300);
//使用疊代器來周遊set集合
Iterator<Integer> iterator = integers.iterator();
while (iterator.hasNext()) {
Integer next = iterator.next();
System.out.println(next);
}
}
}
LinkedHashSet集合
LinkedHashSet底層的資料結構是連結清單和哈希表
連結清單保證有序 哈希表保證元素唯一
LinkedHashSet集合的特點:元素有序 , 并且唯一
代碼:
public class MyTest {
public static void main(String[] args) {
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("張三");
linkedHashSet.add("李四");
linkedHashSet.add("王五");
linkedHashSet.add("趙六");
linkedHashSet.add("田七");
linkedHashSet.add("劉八");
linkedHashSet.add("張三");
linkedHashSet.add("李四");
linkedHashSet.add("王五");
linkedHashSet.add("趙六");
linkedHashSet.add("田七");
linkedHashSet.add("劉八");
for (String s : linkedHashSet) {
System.out.println(s);
}
}
}
TreeSet集合
TreeSet集合的特點: 元素唯一,并且可以對元素進行排序
排序:
a: 自然排序 使用的是無參構造
注意:使用TreeSet集合進行元素的自然排序,那麼對元素有要求,要求這個元素
必須實作Comparable接口 否則無法進行自然排序
Comparable接口中需要重寫comparaTo方法, 保證元素的唯一性是靠compareTo方法的傳回值來确定如果傳回0 表示兩個元素相等,則不重複存儲
b: 使用比較器排序
到底使用的是哪一種的排序取決于,構造方法.
TreeSet集合保證元素唯一性圖解
1.自然排序:
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 int compareTo(Student o) {
int num = this.age - o.age;
int num2 = num == 0 ? this.name.compareTo(o.name) : num;
//從小到大
return num2;
//從大到小
//return -num2;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class MyTest {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(new Student("張三",33));
treeSet.add(new Student("李四", 24));
treeSet.add(new Student("王五", 38));
treeSet.add(new Student("趙六", 26));
treeSet.add(new Student("張三", 33));
treeSet.add(new Student("張三", 33));
treeSet.add(new Student("王老五", 33));
for (Student student : treeSet) {
System.out.println(student.getName()+"==="+student.getAge());
}
}
}
2.比較器排序:
public class MyTest {
public static void main(String[] args) {
/* 構造方法摘要
TreeSet()
構造一個新的空 set,該 set 根據其元素的自然順序進行排序。*/
/* TreeSet(Comparator < ? super E > comparator)
構造一個新的空 TreeSet,它根據指定比較器進行排序。*/
// Comparator 接口 強行對某個對象 collection 進行整體排序 的比較函數。
//采用比較器排序,根據比較器中的compare()這個方法的傳回值的正負0 來決定元素在二叉樹中放置的位置
TreeSet<Integer> treeSet = new TreeSet<>(new Comparator<Integer>() {
@Override
public int compare(Integer a, Integer b) {
return a-b;
}
});
treeSet.add(20);
treeSet.add(20);
treeSet.add(20);
treeSet.add(10);
treeSet.add(200);
treeSet.add(30000);
treeSet.add(120);
treeSet.add(200);
treeSet.add(20999);
for (Integer integer : treeSet) {
System.out.println(integer);
}
}
}
案例:需求:編寫一個程式,擷取10個1至20的随機數,要求随機數不能重複。
public class MyTest {
public static void main(String[] args) {
//需求:編寫一個程式,擷取10個1至20的随機數,要求随機數不能重複。
Random random = new Random();
LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();
while (linkedHashSet.size() < 10) {
int num = random.nextInt(20) + 1;
linkedHashSet.add(num);
}
System.out.println(linkedHashSet);
}
}
案例:
案例示範:
需求:鍵盤錄入3個學生資訊(姓名, 國文成績, 數學成績, 英語成績), 按照總分從高到低輸出到控制台
代碼:
public class Student{
//姓名,國文成績,數學成績,英語成績
private String name;
private int chineseScore;
private int mathScore;
private int englishScore;
public Student() {
}
public Student(String name, int chineseScore, int mathScore, int englishScore) {
this.name = name;
this.chineseScore = chineseScore;
this.mathScore = mathScore;
this.englishScore = englishScore;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChineseScore() {
return chineseScore;
}
public void setChineseScore(int chineseScore) {
this.chineseScore = chineseScore;
}
public int getMathScore() {
return mathScore;
}
public void setMathScore(int mathScore) {
this.mathScore = mathScore;
}
public int getEnglishScore() {
return englishScore;
}
public void setEnglishScore(int englishScore) {
this.englishScore = englishScore;
}
//提供一個擷取總分的方法
public int getTotalScore(){
return chineseScore+mathScore+englishScore;
}
}
public class MyTest {
public static void main(String[] args) {
TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getTotalScore() - s2.getTotalScore();
//考慮同分的情況,總分一樣,并不能說名是同一個學生,還得比較一下姓名
int num2=num==0?s1.getName().compareTo(s2.getName()):num;
return -num2;//降序排列
}
});
for (int i = 1; i <= 3; i++) {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入第"+i+"個學生的姓名");
String name = sc.nextLine();
System.out.println("請輸入第"+i+"個學生的國文成績");
int yw = sc.nextInt();
System.out.println("請輸入第"+i+"個學生的數學成績");
int sx = sc.nextInt();
System.out.println("請輸入第" + i + "個學生的英語成績");
int yy = sc.nextInt();
//建立學生對象,把錄入的資訊,封裝到學生學生對象裡面
Student student = new Student(name, yw, sx, yy);
treeSet.add(student);
}
//按照總分高低排序,輸出學生的資訊。
System.out.println("名次\t姓名\t國文\t數學\t英語\t總分");
int i=0;
for (Student student : treeSet) {
System.out.println((++i)+"\t"+student.getName()+"\t"+student.getChineseScore()+"\t"+student.getMathScore()+"\t"+student.getEnglishScore()+"\t"+student.getTotalScore());
}
}
}
.add(student);
}
//按照總分高低排序,輸出學生的資訊。
System.out.println("名次\t姓名\t國文\t數學\t英語\t總分");
int i=0;
for (Student student : treeSet) {
System.out.println((++i)+"\t"+student.getName()+"\t"+student.getChineseScore()+"\t"+student.getMathScore()+"\t"+student.getEnglishScore()+"\t"+student.getTotalScore());
}
}
}