第一章 List集合
1.List集合介绍
List接口继承自Collection接口,是单列集合的一个重要分支。习惯把所有实现list接口的对象称之为list集合。在list集合中允许出现重复的元素,所有元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合指定元素,List集合是有序的,也就是说存入的顺序和取出的顺序是一致的。
2.List集合常用方法
List作为Collection集合的子接口,继承了Collection中的全部方法,而且还增加了一些特有方法:
-
public void add(int index ,E element): 将指定的元素,添加到该集合中的指定位置上。
-
public E get(int index): 返回集合中指定位置的元素
-
public E remove(int index): 移除列表中指定位置的元素,返回的是被移除的元素。
-
public E set(int index ,E element): 用来指定元素替换集合中指定位置的元素,返回的是更新前的元素
List集合的特有方法都跟索引有关。
其实List接口下有很多集合 ,他们有什么区别呢? 其实就是数据结构不同。
第二章 数据结构
1.数据结构介绍
数据结构: 数据用什么样的方式组合在一起的。
2.常见数据结构
数据存储的常见结构有:栈、队列、数组、链表、红黑树.....
栈
-
栈:stack,也可以叫堆栈,它是运算受限的线性表,限制的是仅允许在一端进行插入和删除操作,不允许在其他位置进行添加、查找、删除等操作。
用该结构的集合 有以下特点。
-
先进后出(存进去的元素,要在它后面的元素依次取出后才能取出该元素)。例如子弹压进弹夹。
-
栈的入口和出口都是栈的顶端位置。
-
压栈:就是存元素。也就是说把元素存储到栈的顶端,栈中已经有的元素依次向栈底移动一个位置。
-
弹栈:就是取元素。也就是把栈的顶端位置元素取出,栈中已有的元素依次向栈顶端移动一个位置。
队列
-
队列:queue,简称队,也是一种运算受限的线性表,限制的是仅允许在表的一端进行插入,另一端进行删除。
-
先进先出(存进去的元素,要在后它前面的元素依次取出后,才能取出该元素)火车过隧道。
-
队列的入口、出口各占一侧。例如 左侧为入口、右侧为出口
数组
-
数组:array,是有序的元素序列,数组是在内存中开辟一段连续的空间,并在此存放元素。例如 有100个出租房,001 到100 每个房间固定编号,通过编号可以快速找到对应的人。
特点:
-
查找元素快:存储元素的地址值是连续的,数组长度固定,可以通过索引,快速的访问到指定位置的元素。(数据地址=首元素地址+偏移量)
-
增删元素慢
-
在指定位置增加元素:需要创建一个新的数组,将指定新元素存储在指定索引位置,再把原数组元素根据索引 复制到新数组对应索引位置。
-
指定索引位置删除元素:需要创建一个新数组,把原数组的元素根据索引,复制到新数组对应索引位置,原数组中指定索引位置元素不复制。
链表
-
链表:linked list,由一系列结点node(链表中每一个元素称之为结点)组成,结点可以在运行时动态生成。每个结点包含两个部分:一个部分存储数据元素的数据域,另一个存储下一个结点地址值的指针域。我们常说的链表结构有单向链表与双向链表。
-
链表结构:
-
多个结点之间,通过地址进行链接。例如手拉手,每个人的右手连着下一个人的左手,依次类推 多个人就连接到一起了。
-
查找元素慢: 想要查找某个元素,需要通过连接的结点,依次向后查找指定元素。
-
增删元素快: 红线表示添加节点,蓝线表示删除节点过程:
红黑树
-
二叉树:binary tree ,就是每个结点不超过2的有序树。
二叉树是每个结点最多有两个子树的树结构。顶上的叫根节点,两边分别称作左子树和右子树。
红黑树是二叉树的一种,可以通过黑红结点尽可能的保证二叉树的平衡,从而提高效率。
红黑树的约束:
1.节点可以是红色或者黑色的。
2.根节点必须是黑色的。
3.叶子节点(特指空节点)是黑色的。
4.每个红色节点的子节点都是黑色的。
5.任何一个节点到每一个叶子节点的所有路径上的黑色节点数量相同。
速度特别快,趋近于平衡树,查找叶子元素最多和最少的次数不多于两倍。
如:
第三章 List的实现类
1.ArrayList集合
ArrayList是数组结构。元素增删慢、查找快。用于日常开发中使用最多的功能为查询数据、遍历数据。 所以ArrayList是最常用的集合。
实际开发中很多程序员都随意的使用ArrayList完成任何需求,这种做法是不提倡的。
2.LinkedList集合
java.util.LinkedList集合存储数据的结构是链表结构 ,方便元素的添加、删除的集合。
LinkedList是一个双向链表,如图;
实际开发中经常会对集合进行添加或者删除 ,最常涉及的就是首尾操作,Linkedlist提供了大量的首尾操作方法。
-
public void addFirst(E e): 将指定元素插入到列表的开头
-
public void addLast(E e):将指定元素添加到列表的结尾
-
public E getFirst(): 返回此列表的第一个元素
-
public E getLast(): 返回此列表的最后一个元素
-
public E removeFirst(): 移除并返回此列表的第一个元素
-
public E removeLast(): 移除并返回此列表的最后一个元素
-
public boolean isEmpty(): 如果列表不包含元素 则返回true
LinkedList是List的实现类。List中的方法LinkedList都可以使用。
第四章 Set接口
1.Set集合介绍
List接口和Set接口都继承于Collection接口 接口中方法基本一致,并没有对Collection接口进行功能上的扩充,只是比Collection更严格了。Set接口与List接口不同的是 Set接口中元素无序,并且都会以某种规则保证元素不出现重复。
Set集合有很多实现类,我们主要介绍其中的java.util.HashSet、java.util.LinkedHashSet这两个集合。
Set集合取出元素方式可以采用:迭代器、增强for
2.HashSet集合介绍
存储的元素是不重复的,并且元素都是无序的。
代码示例:
public class Demo01 {
public static void main(String[] args) {
//创建set集合
HashSet<String> set=new HashSet<>();
//添加元素
set.add("abc1");
set.add("abc2");
set.add("abc3");
set.add("abc4");
set.add("abc");//直接添加
set.add(new String("qqq"));//创建添加
String str = "www";
set.add(str);//引用添加
set.add("qqq");//重复添加了但是不会被打印
System.out.println("qqq".hashCode());
System.out.println("abc".hashCode());
//是根据hashCode()表排序,但不是大小顺序,有一定规律
//遍历集合
for (String s : set) {
System.out.println("s = "+s);
}
}
}
3.HashSet集合存储数据的结构(哈希表)
什么是哈希表?
jdk1.8之前,哈希表底层采用数据+链表实现,也就是使用数组处理冲突,同一hash值的链表都存储在一个数组中。当链表长度不平衡或者过高查找效率就变低了,jdk1.8之后,哈希表采用数组+链表+红黑树的方式实现,也就是说当链表长度超过8时,将链表转换为红黑树,大大的减少了查询时间。
这个到底是怎么存储的?
HashSet存储原理----也就是HashMap底层
开始计算索引,做逻辑判断。
总结: 1.8引入了红黑树大程度的优化了hashMap的性能。
对于我们来说如何保证hashset集合元素的唯一性?其实就是根据对象的hashCode和equals方法来决定的 。如果我们往集合中存放自定义对象,那么保证唯一,就必须重写hashCode和equals方法建立属于当前对象的比较方式。
4.HashSet存储自定义类型元素
给HashSet中存放自定义类型的元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方法,才能保证HashSet集合中的对象唯一性。
如用HashSet存储学生姓名和年龄并遍历打印成员信息:
import java.util.Objects;
public class Student {
private String name;
private int age;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", 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;
return age == student.age && //地址不相同但类型相同情况下比较内容
Objects.equals(name, student.name);//两个参数的equal对比
}
@Override
public int hashCode() {
return Objects.hash(name, 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;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
import java.util.HashSet;
public class Demo02 {
public static void main(String[] args) {
HashSet<Student> students=new HashSet<>();
students.add(new Student("张飞",33));
students.add(new Student("关羽",23));
students.add(new Student("张飞",33));
//两个张飞,因为new了两次,认为是两个不同地址所以不重写hashCode和equals方法也会打印两次
//但我重写hashCode和equals方法后就只能保留一个了,没重写时只对比了地址。
Student stu=new Student("刘备",22);
students.add(stu);//因为只new了一次,认为两次添加同一地址元素,未重写也只保存一个刘备
students.add(stu);
for (Student student : students) {
System.out.println("students = "+student);
}
}
}
5.LinkedHashSet
可以保证元素有序且唯一,HashSet下有一个子类,java.util.LinkedHashSet,它是链表和哈希表组合的一个数据结构。
代码演示:
public class Demo03 {
public static void main(String[] args) {
Set<String> set=new LinkedHashSet<>() ;//有序且唯一去重
set.add("aaa");
set.add("bbb");
set.add("ccc");
set.add("ddd");
set.add("eee");
set.add("aaa");
set.add("aaa");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
第五章Collections类
1.Collections常用功能
-
java.utils.Collections 是集合的工具类 用来提供对集合进行操作的方法。
-
public static void shuffle(List<E> list) :打乱集合顺序。
-
public static <T> void sort (List<T> list): 将集合中元素按照默认的规则进行排序(如果是基本数据类型会根据数字大小顺序排序;如果是String类型会根据首字母ASCII来排序);
-
public static <T> void sort(List<T> list,Comparator<? super T>): 将集合中的元素按照指定规则排序。(自定义类型按自己想要的要求排序时就不能只用Collections.sort(list1),还外加了一个比较器)
如学生类按年龄排序
ArrayList<Student> list2=new ArrayList<>();
list2.add(new Student("张飞",33));
list2.add(new Student("关羽",23));
list2.add(new Student("刘备",35));
Collections.sort(list2, new Comparator<Student>() {
@Override
public int compare(Student t1, Student t2) {
return t1.getAge()-t2.getAge();//升序
}
});
如定义一个ArrayList类,用来存储1-10之间的数 1.打乱顺序输出 2.从小到大输出 3.从大到小输出
public class Demo04 {
public static void main(String[] args) {
ArrayList<Integer>list=new ArrayList<>();
for (int i = 1; i <=10 ; i++) {
list.add(i);
}
Collections.shuffle(list);
System.out.println("打乱顺序后list = " + list);
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer t1, Integer t2) {
return t1-t2;
}
});
System.out.println("从小到大list = " + list);
//将本已排好正序的序列倒转成逆序
Collections.sort(list,Collections.reverseOrder());
System.out.println("从大到小list = " + list);
}
}
回顾小练习:编写一个22选5的彩票选号系统,每次选出不同的五组号码,并输出到控制台中。
分析:方法1.删除集合中元素 删除到只剩下五个。
方法2.采用随机数随机抽取五个不同的数放入新集合中,每次随机出来的需要判断新集合中是否包含 如果包含需要重新随机 直到新集合中够5个位置。
public class Demo05 {
public static void main(String[] args) {
List<Integer> numbers =new ArrayList<>();
for (int i = 1; i <= 22 ; i++) {
numbers.add(i);
}
Random random =new Random();
//第一种,随机删元素,直到只剩5个
// while(numbers. size ()>5) {
// int index = random.nextInt(numbers.size());
// numbers.remove(index);
// }
// System.out.println("numbers = " + numbers);
//第二种,随机拿5个到新数组
List<Integer> result =new ArrayList<>();
while (result.size()<5){
int index = random.nextInt(numbers.size());
int number = numbers.get(index);
if (!result.contains(number)){
result.add(number);
numbers.remove(index);
}
}
System.out.println("result = " + result);
}
}