您的位置:首页 > 其它

17. 集合类 (Set的子类HashSet、LinkedHashSet、TreeSet)

2017-12-17 16:14 375 查看

2:Set集合(理解)

(1)Set集合的特点

无序,唯一

(2)HashSet集合(掌握)

它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。

* 注意:虽然Set集合的元素无序,但是,作为集合来说,它肯定有它自己的存储顺序,

A:底层数据结构是哈希表(是一个元素为链表的数组)

B:哈希表底层依赖两个方法:hashCode()和equals()

执行顺序:

首先比较哈希值是否相同

相同:继续执行equals()方法

返回true:元素重复了,不添加

返回false:直接把元素添加到集合

&nb
4000
sp; 不同:就直接把元素添加到集合

C:如何保证元素唯一性的呢?

由hashCode()和equals()保证的

D:开发的时候,代码非常的简单,自动生成即可。

E:HashSet存储字符串并遍历

public class SetDemo {
publicstatic void main(String[] args) {
//创建集合对象
Set<String>set = new HashSet<String>();
//创建并添加元素
set.add("hello");
set.add("java");
set.add("world");
set.add("java");
set.add("world");
//增强for
for(String s : set) {
System.out.println(s);
}
}
}

F:HashSet存储自定义对象并遍历(对象的成员变量值相同即为同一个元素)

public class Student {
privateString name;
privateint age;
publicStudent() {
super();
}
publicStudent(String name, int age) {
super();
this.name= name;
this.age= age;
}
publicString getName() {
returnname;
}
publicvoid setName(String name) {
this.name= name;
}
publicint getAge() {
returnage;
}
publicvoid setAge(int age) {
this.age= age;
}
@Override
publicint hashCode() {
finalint prime = 31;
intresult = 1;
result= prime * result + age;
result= prime * result + ((name == null) ? 0 : name.hashCode());
returnresult;
}
@Override
publicboolean equals(Object obj) {
if(this == obj)
returntrue;
if(obj == null)
returnfalse;
if(getClass() != obj.getClass())
returnfalse;
Studentother = (Student) obj;
if(age != other.age)
returnfalse;
if(name == null) {
if(other.name != null)
returnfalse;
}else if (!name.equals(other.name))
returnfalse;
returntrue;
}
//@Override
//public int hashCode() {
//// return 0;
//// 因为成员变量值影响了哈希值,所以我们把成员变量值相加即可
//// return this.name.hashCode() + this.age;
//// 看下面
//// s1:name.hashCode()=40,age=30
//// s2:name.hashCode()=20,age=50
//// 尽可能的区分,我们可以把它们乘以一些整数
//return this.name.hashCode() + this.age * 15;
//}
//@Override
//public boolean equals(Object obj) {
//// System.out.println(this + "---" + obj);
//if (this == obj) {
//return true;
//}
//if (!(obj instanceof Student)) {
//return false;
//}
//Student s = (Student) obj;
//return this.name.equals(s.name) && this.age == s.age;
//}
//@Override
//public String toString() {
//return "Student [name=" + name + ", age=" + age +"]";
//}
}

* 需求:存储自定义对象,并保证元素的唯一性

* 要求:如果两个对象的成员变量值都相同,则为同一个元素。

* 目前是不符合我的要求的:因为我们知道HashSet底层依赖的是hashCode()和equals()方法。

* 而这两个方法我们在学生类中没有重写,所以,默认使用的是Object类。

* 这个时候,他们的哈希值是不会一样的,根本就不会继续判断,执行了添加操作。

public class HashSetDemo2 {
publicstatic void main(String[] args) {
//创建集合对象
HashSet<Student>hs = new HashSet<Student>();
//创建学生对象
Students1 = new Student("林青霞",27);
Students2 = new Student("柳岩",22);
Students3 = new Student("王祖贤",30);
Students4 = new Student("林青霞",27);
Students5 = new Student("林青霞",20);
Students6 = new Student("范冰冰",22);
//添加元素
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
hs.add(s5);
hs.add(s6);
//遍历集合
for(Student s : hs) {
System.out.println(s.getName()+ "---" + s.getAge());
}
}
}

(3)LinkedHashSet

底层数据结构由哈希表和链表组成。

哈希表保证元素的唯一性。

链表保证元素有素。(存储和取出是一致)

public class LinkedHashSetDemo {
publicstatic void main(String[] args) {
//创建集合对象
LinkedHashSet<String>hs = new LinkedHashSet<String>();
//创建并添加元素
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
hs.add("java");
//遍历
for(String s : hs) {
System.out.println(s);
}
}
}

(4)TreeSet集合(保证元素唯一性,保证元素的排序)

A:底层数据结构是红黑树(是一个自平衡的二叉树)

B:保证元素的排序方式

a:自然排序(元素具备比较性)

让元素所属的类实现Comparable(自然排序)接口

b:比较器排序(集合具备比较性)

让集合构造方法接收Comparator(比较器)的实现类对象

C:把我们讲过的代码看一遍即可

注意:如果同时有自然排序和比较器排序,以比较器排序为主

public class TreeSetDemo {
publicstatic void main(String[] args) {
//创建集合对象
//自然顺序进行排序
TreeSet<Integer>ts = new TreeSet<Integer>();
//创建元素并添加
//20,18,23,22,17,24,19,18,24
ts.add(20);
ts.add(18);
ts.add(23);
ts.add(22);
ts.add(17);
ts.add(24);
ts.add(19);
ts.add(18);
ts.add(24);
//遍历
for(Integer i : ts) {
System.out.println(i);
}
}
}

(4)案例:

A:获取无重复的随机数

* 分析:

* A:创建随机数对象

* B:创建一个HashSet集合

* C:判断集合的长度是不是小于10

* 是:就创建一个随机数添加

* 否:不搭理它

* D:遍历HashSet集合

public class HashSetDemo {
publicstatic void main(String[] args) {
//创建随机数对象
Randomr = new Random();
//创建一个Set集合
HashSet<Integer>ts = new HashSet<Integer>();
//判断集合的长度是不是小于10
while(ts.size() < 10) {
intnum = r.nextInt(20) + 1;
ts.add(num);
}
//遍历Set集合
for(Integer i : ts) {
System.out.println(i);
}
}
}

B:键盘录入学生按照总分从高到底输出

* 分析:

* A:定义学生类

* B:创建一个TreeSet集合

* C:总分从高到底如何实现呢?

* D:键盘录入5个学生信息

* E:遍历TreeSet集合

public class TreeSetDemo {
publicstatic void main(String[] args) {
//创建一个TreeSet集合
TreeSet<Student>ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
publicint compare(Student s1, Student s2) {
//总分从高到低
intnum = s2.getSum() - s1.getSum();
//总分相同的不一定语文相同
intnum2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
//总分相同的不一定数序相同
intnum3 = num2 == 0 ? s1.getMath() - s2.getMath() : num2;
//总分相同的不一定英语相同
intnum4 = num3 == 0 ? s1.getEnglish() - s2.getEnglish() : num3;
//姓名还不一定相同呢
intnum5 = num4 == 0 ? s1.getName().compareTo(s2.getName())
:num4;
returnnum5;
}
});
System.out.println("学生信息录入开始");
//键盘录入5个学生信息
for(int x = 1; x <= 5; x++) {
Scannersc = new Scanner(System.in);
System.out.println("请输入第" + x + "个学生的姓名:");
Stringname = sc.nextLine();
System.out.println("请输入第" + x + "个学生的语文成绩:");
StringchineseString = sc.nextLine();
System.out.println("请输入第" + x + "个学生的数学成绩:");
StringmathString = sc.nextLine();
System.out.println("请输入第" + x + "个学生的英语成绩:");
StringenglishString = sc.nextLine();
//把数据封装到学生对象中
Students = new Student();
s.setName(name);
s.setChinese(Integer.parseInt(chineseString));
s.setMath(Integer.parseInt(mathString));
s.setEnglish(Integer.parseInt(englishString));
//把学生对象添加到集合
ts.add(s);
}
System.out.println("学生信息录入完毕");
System.out.println("学习信息从高到低排序如下:");
System.out.println("姓名\t语文成绩\t数学成绩\t英语成绩");
//遍历集合
for(Student s : ts) {
System.out.println(s.getName()+ "\t" + s.getChinese() + "\t"
+s.getMath() + "\t" + s.getEnglish());
}
}
}


public class Student {
//姓名
privateString name;
//语文成绩
privateint chinese;
//数学成绩
privateint math;
//英语成绩
privateint english;
publicStudent(String name, int chinese, int math, int english) {
super();
this.name= name;
this.chinese= chinese;
this.math= math;
this.english= english;
}
publicStudent() {
super();
}
publicString getName() {
returnname;
}
publicvoid setName(String name) {
this.name= name;
}
publicint getChinese() {
returnchinese;
}
publicvoid setChinese(int chinese) {
this.chinese= chinese;
}
publicint getMath() {
returnmath;
}
publicvoid setMath(int math) {
this.math= math;
}
publicint getEnglish() {
returnenglish;
}
publicvoid setEnglish(int english) {
this.english= english;
}
publicint getSum() {
return this.chinese + this.math + this.english;
}
}

3:Collection集合总结(掌握)

Collection

|--List
有序(存储顺序和取出顺序一致),可重复

|--ArrayList

底层数据结构是数组,查询快,增删慢。

线程不安全,效率高

|--Vector被ArrayList替代

底层数据结构是数组,查询快,增删慢。

线程安全,效率低

|--LinkedList

底层数据结构是链表,查询慢,增删快。

线程不安全,效率高

|--Set
无序(存储顺序和取出顺序不一致),唯一

|--HashSet

底层数据结构是哈希表。线程不同步,效率高

如何保证元素唯一性的呢?

依赖两个方法:hashCode()和equals()

开发中自动生成这两个方法即可

|--LinkedHashSet
(存储顺序和取出顺序一致)

底层数据结构是链表和哈希表

由链表保证元素有序

由哈希表保证元素唯一

|--TreeSet

底层数据结构是红黑树。线程不同步,效率高

如何保证元素排序的呢?

自然排序

比较器排序

如何保证元素唯一性的呢?

根据比较的返回值是否是0来决定

4:针对Collection集合我们到底使用谁呢?(掌握)

唯一吗?

是:Set

排序吗?

是:TreeSet

否:HashSet

如果你知道是Set,但是不知道是哪个Set,就用HashSet。

否:List

要安全吗?

是:Vector

否:ArrayList或者LinkedList

查询多:ArrayList

增删多:LinkedList

如果你知道是List,但是不知道是哪个List,就用ArrayList。

如果你知道是Collection集合,但是不知道使用谁,就用ArrayList。

如果你知道用集合,就用ArrayList。

5:在集合中常见的数据结构(掌握)

ArrayXxx: 底层数据结构是数组,查询快,增删慢

LinkedXxx: 底层数据结构是链表,查询慢,增删快

HashXxx: 底层数据结构是哈希表。依赖两个方法:hashCode()和equals()

TreeXxx: 底层数据结构是二叉树。两种方式排序:自然排序和比较器排序

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐