第二十三章
一、 数据结构
1.1 栈
1.2 队列
1.3 数组
1.4 链表
1.5 红黑树
二、 List集合
2.1 List集合常用的方法
java.util.list 接口 extends Collection接口
List接口的特点:
1.有序的集合,存储元素和取出元素的顺序是一只的(存储123 取出123)
2.有索引,包含了一些带索引的方法
3.允许存储重复的元素
List接口中带索引的方法(特有)
public void add(int index ,E element):将指定的元素添加到该集合的指定位置上
public E get(int index):返回集合中指定位置的元素
public E remove(int index):移除列表中指定位置的元素,返回的是被一处的元素
public E set(int index,E element):用指定元素替换集合中指定位置的元素,返回更新前的元素
注意:
操作索引的时候,一定要防止索引越界异常
IndexOutOfBoundsException集合索引越界异常
ArrayOutOfBoundsException数组索引越界异常
StringOutOfBoundsException字符串索引越界异常
public class Demo01list {
public static void main(String[] args) {
//创建一个list集合对象,多态
List<String> list = new ArrayList<>();
//使用add方法往集合中添加元素
list.add("a");
list.add("b");
list.add("c");
list.add("a");
//打印集合
System.out.println(list);//不是地址,[a, b, c, a],重写了toString方法
//public void add(int index ,E element):将指定的元素添加到该集合的指定位置上
list.add(3,"d");
System.out.println(list);//[a, b, c, d, a]
//public E remove(int index):移除列表中指定位置的元素,返回的是被一处的元素
String remove = list.remove(2);
System.out.println("被移除的是"+ remove);
System.out.println(list);//[a, b, d, a]
// public E set(int index,E element):用指定元素替换集合中指定位置的元素,返回更新前的元素
String a = list.set(3, "A");
System.out.println("被替换的元素是"+a);
System.out.println(list);//[a, b, d, A]
//list集合遍历有三种方式
//使用普通的for循环
for(int i = 0;i < list.size();i++){
//public E get(int index):返回集合中指定位置的元素
String str = list.get(i);
System.out.println(str);
}
System.out.println("------------");
//使用迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()){
String str= it.next();
System.out.println(str);
}
System.out.println("--------------");
//使用增强for循环
for (String s:list
) {
System.out.println(s);
}
// String s = list.get(5);//IndexOutOfBoundsException 5超出数组长度,索引越界异常
// System.out.println(s);
}
}
2.2 ArrayList集合
查询快(地址是连续的),增删慢(每添加一个元素,底层就要复制一个集合)
List 接口的大小可变数组的实现。
注意,此实现不是同步的 即多线程
2.3 LinkedList集合
List 接口的链接列表实现。注意,此实现不是同步的 即多线程
java.util.linkedList集合 implements List接口
LinkedList集合的特点:
1.底层是一个链表结构:查询慢,增删快
2.里边包含了大量操作首尾元素的方法
注意:使用LinkList集合特有的方法不能使用多态
public E void addFirst(E e)将指定元素插入此列表的开头
public E void addLast(E e)将指定元素添加到此列表的结尾
public E void push(E e)将元素推入此列表所表示的堆栈。
public E getFirst() 返回此列表的第一个元素
public E getLast() 返回此列表的最后一个元素
public E removeFirst 移除并返回此列表的第一个元素
public E removeLast 移除并返回此列表的最后一个元素
public E pop() 从此列表所表示的堆栈处弹出一个元素
public boolean isEmpty() 如果列表不包含元素,返回true
public class Demo02linkedList {
public static void main(String[] args) {
show01();
show02();
show03();
}
/*
public E removeFirst 移除并返回此列表的第一个元素
public E removeLast 移除并返回此列表的最后一个元素
public E pop() 从此列表所表示的堆栈处弹出一个元素
*/
private static void show03() {
//创建一个LinkedList集合对象
LinkedList<String> linked = new LinkedList<>();
//使用add方法往集合中添加元素
linked.add("a");
linked.add("b");
linked.add("c");
System.out.println(linked);//[a, b, c]
String s1 = linked.removeFirst();
System.out.println("移除第一个元素"+ s1);//a
System.out.println(linked);//[b, c]
String s2 = linked.removeLast();
System.out.println("移除最后一个元素"+s2);//b
System.out.println(linked);//[b]
}
private static void show02() {
//创建一个LinkedList集合对象
LinkedList<String> linked = new LinkedList<>();
//使用add方法往集合中添加元素
linked.add("a");
linked.add("b");
linked.add("c");
// linked.clear();//清空元素
if (!linked.isEmpty()){
//getFirst() getLast()
String first = linked.getFirst();
String last = linked.getLast();
System.out.println(last);//c
System.out.println(first);//a
}
}
/*
void addFirst(E e)将指定元素插入此列表的开头
void addLast(E e)将指定元素添加到此列表的结尾
void push(E e)将元素推入此列表所表示的堆栈。
*/
private static void show01() {
//创建一个LinkedList集合对象
LinkedList<String> linked = new LinkedList<>();
//使用add方法往集合中添加元素
linked.add("a");
linked.add("b");
linked.add("c");
System.out.println(linked);//[a, b, c]
// void addFirst(E e)将指定元素插入此列表的开头
linked.addFirst("www");
System.out.println(linked);//[www, a, b, c]
//void push(E e)将元素推入此列表所表示的堆栈。
linked.push("www");
System.out.println(linked);//[www, www, a, b, c]
//void addLast(E e)将指定元素添加到此列表的结尾
linked.addLast("com");
System.out.println(linked);
System.out.println("-----------");
}
}
2.4 Vector集合(1.0版本的集合,了解)
从 Java 2 平台 v1.2 开始,此类改进为可以实现 List 接口,使它成为 Java Collections Framework 的成员。与新 collection 实现不同,Vector 是同步的
三、HashSet集合介绍
3.1 HashSet概述
一个不包含重复元素的 collection
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。 注意,此实现不是同步的
JAVA.util.Set接口: extends Collection接口
Set接口特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
java.util.HashSet集合 implements Set 接口
HashSet特点:
1.不允许存储重复的元素
2.没有索引,没有带索引的方法,也不能使用普通for循环遍历
3.是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4.底层是一个哈希表结构(查询的速度非常快)
public class Demo01Set {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
//使用add方法往集合添加元素
set.add(1);
set.add(3);
set.add(2);
set.add(1);
//使用迭代器遍历set集合
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
Integer n = it.next();
System.out.println(n);//1 2 3 不能存储相同元素,所以之只有一个1
}
//增强for
// for (Integer n : set
// ) {
// System.out.println(n);
//
// }
//set集合是没有索引的所以不能用普通的for循环
}
}
3.2 哈希值
哈希值:
是一个十进制的整数,由系统随机给出
(就是对象的地址,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)
在Object类有一个方法,可以获取对象的哈希值
int hashCode() 返回该对象的哈希码值。
HashCode方法的源码
public native int hashCode();
native:代表该方法调用的是本地操作系统的方法
public class Demo01HashCode {
public static void main(String[] args) {
//Person 类继承了Object类,所以可以使用Object类的HashCode方法
Person p1 = new Person();
int i1 = p1.hashCode();
System.out.println(i1);//381259350 //在Person类中重写后,方法内写的多少返回多少 1
Person p2 = new Person();
int i2 = p2.hashCode();
System.out.println(i2);//2129789493//在Person类中重写后 法内写的多少返回多少1
/*
toString方法的源码:
public String toString() {
return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());
}
*/
//等同于哈希值
System.out.println(p1);//cn.itcast.day13.demo02.Person@16b98e56//在Person类中重写后 Person@1
System.out.println(p2);//cn.itcast.day13.demo02.Person@7ef20235//在Person类中重写后 Person@1
System.out.println(p1 == p2); //false 哈希地址(逻辑地址)相同,物理地址不同
/*
String类的哈希值
String类重写Object类的hashCode方法
*/
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.hashCode());//96354(逻辑/哈希地址)
System.out.println(s2.hashCode());//96354(逻辑/哈希地址)
System.out.println("重地".hashCode());//1179395 (逻辑/哈希地址)
System.out.println("通话".hashCode());//1179395(逻辑/哈希地址)
}
}
3.3 哈希Set存储数据的结构(哈希表)
3.4 Set集合元素不重复的原理
3.5 哈希Set存储自定义类型的元素
给HashSet中存放自定义元素时,需要重写对象中的hashCode方法和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
import java.util.HashSet;
/*
HashSet存储自定义元素
set集合报错,元素唯一:
存储的元素(String,Integer....Student,Person),必须重写hashCode方法和equals方法
要求:
同名同年龄的人,视为同一个人,只能添加一次
*/
public class Demo04HashSetSave {
public static void main(String[] args) {
//创建HashSet集合存储Person
HashSet<Person1> set = new HashSet<>();
Person1 p1 = new Person1("张三",18);
Person1 p2 = new Person1("张三",18);
Person1 p3 = new Person1("张三",19);
//重写后
System.out.println(p1.hashCode());//381259350 | 24022538
System.out.println(p2.hashCode());//2129789493 | 24022538
System.out.println(p1 == p2);//false 物理地址值不同| false
System.out.println(p1.equals(p2));//false | true 重写equals方法后比较的是内容。
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);//没重写重写hashCode方法和equals方法 会有重复元素
//重写后无重复元素[Person1{name='张三', age=18}, Person1{name='张三', age=19}]
}
}
person1类
public class Person1 {
private String name;
private int age;
public Person1(String name, int age) {
this.name = name;
this.age = age;
}
public Person1() {
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person1 person1 = (Person1) o;
return age == person1.age &&
Objects.equals(name, person1.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person1{" +
"name='" + name + '\'' +
", 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;
}
}
3.5 LinkedHashSet集合(HashSet的子类)
具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现
/*
java.util.LinkedHashSet 集合 extends HashSet集合
LinkedHashSet集合特点:
底层是一个哈希表(数组 + 链表/红黑树)+ 链表:多了一层链表(记录元素的存储顺序),保证元素有序
*/
public class Demo05 {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("www");
set.add("abc");
set.add("abc");
set.add("itcast");
System.out.println(set);//[abc, www, itcast] 无序 不允许重复
LinkedHashSet<String> linked = new LinkedHashSet<>();
linked.add("www");
linked.add("abc");
linked.add("abc");
linked.add("itcast");
System.out.println(linked);//[www, abc, itcast] 有序 不允许重复
}
}
四、可变参数
/*
可变参数:是JDK1.5之后出现的新特性
使用前提:
当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
使用方法:
修饰符 返回值类型 方法名(数据类型... 变量名){}
可变参数的原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
传递参数的个数,可以是0个(不传递),1,2,3....多个
*/
public class Demo01VarArgs {
public static void main(String[] args) {
// int i = add();
// int i = add(10);
// int i= add(10,20);
int i= add(10,20,30,40,50,60,70,80,90,100);
// System.out.println(i);
System.out.println(i);
}
/*
可变参数的注意事项:
1.一个方法的参数列表,只可能有一个可变参数
public static void method(int...a,String...){} 有两个会报错
2.如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
public static void method(int a,String b,double c,int...d){}
*/
/*
可变参数的特殊写法:
public static void method(Object...ob){}
*/
/*
定义计算(0-n)整数和的方法
已知:计算整数的和,数据类型已经确定int
但是参数的个数不确定,不知道要计算机个整数的和,就可以使用可变参数
add();就会创建一个长度为0的数组,new int[0]
add(10);就会创建一个长度为1的数组,存储传过来的参数,new int[]{10}
int i= add(10,20);就会创建一个长度为2的数组,存储传过来的参数,new int[] {10,20}
int i= add(10,20,30,40,50,60,70,80,90,100);会创建一个长度为10的数组,
*/
public static int add(int...arr){
//System.out.println(arr);//[I@2d98a335 底层是一个数组 “[”代表是一个数组 "I"代表int类型
// System.out.println(arr.length);// 0 2
//定义一个初始化的变量,记录累加和
int sum = 0;
//遍历数组中的每一个元素
for (int i : arr) {
sum +=i;
}
return sum;
}
// //定义一个方法,计算三个int类型整数的和
// private static int add(int a,int b,int c) {
// return a + b;
//
// }
// //定义一个方法,计算两个int类型整数的和
// private static int add(int a,int b) {
// return a + b;
//
// }
}
五、Collections集合工具类的方法
5.1 Collections集合工具类的方法—addAll&shuffle
/*
java.util.Collections是集合工具类,用来对集合进行操作
static <T> boolean addAll(Collection<T> c, T... elements)将所有指定元素添加到指定 collection 中。
static void shuffle(List<?> list)
使用默认随机源对指定列表进行置换。(打乱集合顺序)
*/
public class Demo01Collections {
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");*/
// static <T> boolean addAll(Collection<T> c, T... elements)将所有指定元素添加到指定 collection 中。
Collections.addAll(list,"a","b","c","d","e");
System.out.println(list);//[a, b, c, d, e]
// static void shuffle(List<?> list)
// 使用默认随机源对指定列表进行置换。(打乱集合顺序)
Collections.shuffle(list);
System.out.println(list);//[e, d, a, c, b]
}
}
5.2 Collections集合工具类的方法—sort(List)
将集合中元素按照默认规则排序
/*
java.util.Collection是集合工具类
public static <T>void sort(List<T> list):将集合中元素按照默认规则排序
注意:
sort(List<T> lsit)使用前提
被排序的集合里边存储的元素,必须实现Comparable,重写接口中的方法compareTo定义排序规则
comparable接口的规则:
自己(this)- 参数:升序
参数 - 自己:降序
*/
public class Demo02Sort {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(3);
list01.add(2);
System.out.println(list01);//[1, 3, 2]
// public static <T>void sort(List<T> list):将集合中元素按照默认规则排序
Collections.sort(list01);
System.out.println(list01);//[1, 2, 3] 默认是升序
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("c");
list02.add("b");
System.out.println(list02);//[a, c, b]
Collections.sort(list02);
System.out.println(list02);//[a, b, c]
ArrayList<Person> list03 = new ArrayList<>();
list03.add(new Person("张三",18));
list03.add(new Person("李四",20));
list03.add(new Person("王五",15));
System.out.println(list03);//[Person{name='张三', age=18}, Person{name='李四', age=18}, Person{name='王五', age=18}]
Collections.sort(list03);//自定义输入的元素,需要重写Comparable类的compareTo方法
System.out.println(list03);//[Person{name='王五', age=15}, Person{name='张三', age=18}, Person{name='李四', age=20}]
}
}
public class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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(Person person) {
// return 0;//认为元素都是相同的
//自己定义比较的规则,比较两个人的年龄(this,参数Person)
// return this.getAge() - person.getAge();//年龄升序排序
return person.getAge() - this.getAge();//年龄降序排序
}
}
5.3 Collections集合工具类的方法—sort(List,Comparator)
将集合中元素按照指定规则排序
/*
java.util.Collection是集合工具类
public static <T> void sort(List<T> ,comparator<? super T>):将集合中元素按照指定规则排序
Comparator 和Comparable的区别
Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写compareTo方法
Comparator:相当于找一个第三方的裁判,比较两个
Comparator规则:
return o1 - o2;//升序
return o2 - o1;//降序[3, 2, 1]
*/
public class Demo03Sort {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(3);
list01.add(2);
System.out.println(list01);//[1, 3, 2]
Collections.sort(list01, new Comparator<Integer>() {
//重写比较的规则comparator
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;//升序
// return o2 - o1;//降序[3, 2, 1]
}
});
System.out.println(list01);//[1, 2, 3]
ArrayList<Student> list02 = new ArrayList<>();
//两个年龄一样,那个写前边,先排哪个
list02.add(new Student("b迪丽热巴",18));
list02.add(new Student("古力娜扎",20));
list02.add(new Student("杨幂",17));
list02.add(new Student("a杨幂",18));
/* Collections.sort(list02, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄升序排列
return o1.getAge() -o2.getAge();
//return 0;
}
});*/
Collections.sort(list02, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄升序排列
int result = o1.getAge() -o2.getAge();
if(result == 0){
//返回的是某个索引下的char值。比如s为“abcde”。那么s.charAt(0)返回的就是索引0对应的值,为a
result = o1.getName().charAt(0)- o2.getName().charAt(0);
}
return result;
}
});
System.out.println(list02);//[Student{name='杨幂', age=17}, Student{name='迪丽热巴', age=18}, Student{name='古力娜扎', age=20}]
}
}
Student类:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", 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;
}
}