文章目录
- 第一章 数据结构
- 常见的数据结构
- 栈
- 队列
- 数组
- 链表
- 红黑树
- 第二章 List集合
- 2.1 List接口介绍
- 2.2 List中的常用方法
- 第三章 List的子类
- 3.1 ArrayList集合
- 3.2 LinkedList集合
- 第四章 Set接口
- 4.1 HashSet集合介绍
- 4.2 HashSet集合存储数据的结构(哈希表)
- Set集合不允许存重复元素的原理
- 4.3 HashSet储存自定义类型元素
- 4.4 LinkedHashSet
- 4.5 可变参数
- 第五章 collections
- 5.1 常用功能
第一章 数据结构
常见的数据结构
栈
- stack又称为栈,他是运算受限的线性表,其限制是仅允许在标的一端进行插入和删除的操作,不允许在其他任何位置进行添加、查找、删除等操作。
特点
- 先进后出
- 栈的入口、出口都是栈的顶端位置
队列
- queue,他和栈一样,都是一种受限的线性表,其限制是仅允许在表的一端进行插入,另一端进行删除
特点
- 先进先出
- 队尾入队、队头出队
数组
懒得看了
链表
懒得看了
红黑树
第二章 List集合
Colltion接口中的两个常用子类java.util.List
和java.util.Set
2.1 List接口介绍
该接口是单列集合的一个重要分支,习惯性地会实现了List接口的对象称为List集合.在LIst集合中允许出现重复的元素,所有的元素以一种线性的方式存储的,他有序(存入顺序和去除顺序一致)
List接口特点
- 他是一个元素存取的有序集合.
- 他是一个带有索引的集合,
- 集合中还可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素,
2.2 List中的常用方法
void add(int index, E element)
在列表的指定位置插入指定元素(可选操作)。
void clear()
从列表中移除所有元素(可选操作)。
E get(int index)
返回列表中指定位置的元素。
int indexOf(Object o)
返回此列表中第一次出现的指定元素的索引;如果此列表不包含该元素,则返回 -1。
E remove(int index)
移除列表中指定位置的元素(可选操作)。
E set(int index, E element)
用指定元素替换列表中指定位置的元素(可选操作)。
int size()
返回列表中的元素数。
Object[] toArray()
返回按适当顺序包含列表中的所有元素的数组(从第一个元素到最后一个元素)。
第三章 List的子类
3.1 ArrayList集合
这个是线性表中的顺序表,元素增删和查找复杂度是n,但是查找快,如果经常需要遍历和查询数据,那么该类是很合适的
3.2 LinkedList集合
该类的数据结构是链表结构(双向链表).方便添加和删除(复杂度为1),但是查找就是慢(复杂度为n)
常用方法:
void add(int index, E element)
在此列表中指定的位置插入指定的元素
void addFirst(E e)
将指定元素插入此列表的开头。
void addLast(E e)
将指定元素添加到此列表的结尾。
void clear()
从此列表中移除所有元素。
E get(int index)
返回此列表中指定位置处的元素。
E pop()
从此列表所表示的堆栈处弹出一个元素。
void push(E e)
将元素推入此列表所表示的堆栈。
E remove()
获取并移除此列表的头(第一个元素)。
E remove(int index)
移除此列表中指定位置处的元素。
E removeFirst()
移除并返回此列表的第一个元素。
E removeLast()
移除并返回此列表的最后一个元素。
E set(int index, E element)
将此列表中指定位置的元素替换为指定的元素。
int size()
返回此列表的元素数。
Object[] toArray()
返回以适当顺序(从第一个元素到最后一个元素)包含此列表中所有元素的数组。
示例:
package Practice;
//其里面包含了大量连接首尾的元素
import java.util.LinkedList;
public class Demo1 {
public static void main(String[] args) {
LinkedList<String> aaa = new LinkedList<>();
//使用add方法来添加元素
aaa.add("a");
aaa.add("b");
aaa.add("c");
System.out.println(aaa);
aaa.addFirst("www");
System.out.println(aaa);
aaa.push("aaaaa");
System.out.println(aaa);
aaa.pop();
System.out.println(aaa);
}
}
第四章 Set接口
该接口并没有对Collection接口进行功能上的拓展,只是比Collection接口更严格了.与LIst接口不同的是,Set接口中无序,并且都会以某种规则保证存入的元素不再重复.
set集合有多个子类,我们在这里介绍java.util.HashSet
,java.util.LinkedHashSet
这两个集合.
//注意: Set集合取出元素的方式也可以使用: 迭代器,增强for
特点:
- 不允许有重复的元素
- 没有索引,没有带索引的方法,也不能使用普通的for循环遍历
package demo03;
import java.util.HashSet;
import java.util.Set;
public class DoudiZhu {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(111);
set.add(211);
set.add(511);
set.add(711);
set.add(411);
set.add(911);
set.add(1011);
set.add(111);
for (Integer integer : set) {
System.out.println(integer);//我们会发现取出的顺序和遍历的顺序不一致,且不允许存进同样的元素
}
}
}
4.1 HashSet集合介绍
特点:
- 无序的集合**,没有带索引的方法**,储存元素和取出元素的顺序有可能不一致
- 此类实现
Set
接口,由哈希表(实际上是一个HashMap
实例)支持。它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用null
元素。
HashSet
是**根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存储和查找性能.**保证元素唯一性的凡是依赖于:hashCode
和equals
方法
哈希值:是一个由十进制的整数,由系统随机给出(实际上给出的就是对象的地址值,只不过是一个逻辑的地址值,是模拟出来得到的地址,不是数据实际的地址值)
- Object类中有个int hashCode()方法可以获取Hash值
public native int hashCode();
- native代表调用的是本地操作系统的方法
他的一些示范和现象
package demo03;
import java.util.ArrayList;
public class DoudiZhu extends Object {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
ArrayList<String> arr1 = new ArrayList<>();
arr1.add("我是你爹");
System.out.println(arr.hashCode());//这个是1
System.out.println(arr1.hashCode());//这个不是空数组了,所以分配了,这个类重写了hashCode方法
GenericMethod aa = new GenericMethod();
System.out.println(aa.hashCode());//1595428806
//字符串类 重写了hashCode方法
String s1 = new String("abc");
String s2 = new String("abc");
//我们会发现他们的值一样
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
//我们会发现下面这两个也一样
System.out.println("我是你爹".hashCode());
System.out.println("我是你大".hashCode());
//但是个数不一样的时候就不一样了
System.out.println("我是你爹".hashCode());
System.out.println("我是你大爷".hashCode());
}
}
4.2 HashSet集合存储数据的结构(哈希表)
在JDK1.8之前,哈希表底层采用数组+链表实现,同同一hash值得链表都储存在一个链表里面。但是当位于一个桶中的元素较多,即hash值相等得元素较多时,通过key值一次查找得效率较低
所以1.8之后,哈希表采用数组+链表+红黑树实现
数组结构: 把元素进行了分组(相同哈希值的元素是一组),链表、红黑树结构把相同哈希值的元素连接到了一起
注意:
- 两个元素要是内容不同,但是哈希值相同,那么就会引起哈希冲突,两个元素就会同时放在一个组中
- 同一组中的数据要是小于8,那么用链表连接,要是大于8,那么就用红黑树连接(因为查询速度会很快)
Set集合不允许存重复元素的原理
- add方法会调用元素的hashCode和equals方法来判断元素是否重复
- 先调用hashCode方法来判断是否有相等哈希值的元素
- 如果有的话,调用equals方法进行两个元素的比较
- 1 如果元素相同的话,那么就不会存储
- 2 如果元素不同的话,那么就会存储,这两个元素形成链表或者红黑树
- 没有的话,就加入
注意:实现的前提是重写了hashCode方法和equals方法
代码测试:
package Practice;
//其里面包含了大量连接首尾的元素
import java.util.HashSet;
import java.util.LinkedList;
public class Demo1 {
public static void main(String[] args) {
HashSet<String> hash = new HashSet<>();
String s1 = new String("abc");
String s2 = new String("abc");
hash.add(s1);
hash.add(s2);
hash.add(s2);
hash.add(s2);
hash.add(s2);
hash.add("种地");
hash.add("通话");
System.out.println(hash);
}
}
//运行结果
[通话, abc, 种地]
4.3 HashSet储存自定义类型元素
给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法
因为不重写的话,新创建的对象,他们的哈希值和地址值都是不一样的,所以说肯定可以存进集合里面
创建Student类
要求:同名同年龄的人,只能存储一次
//Student类
package Practice;
import java.util.Objects;
public class Student {
private String name;
private int 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 && name.equals(student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
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;
}
}
//主函数
package Practice;
import java.util.HashSet;
public class Demo1 {
public static void main(String[] args) {
Student p1 = new Student("小美女",18);
Student p2 = new Student("小美女",18);
HashSet<Student> set = new HashSet<>();
set.add(p1);
set.add(p2);
//在没有对HashCode方法和equals方法重写的时候,这两个还是可以一起存储
//重写了之后就可以了
System.out.println(set);
}
}
4.4 LinkedHashSet
我们知道HashSet保证元素唯一,可以元素存进去是没有顺序的,那么我们要保证有序,要怎么办呢?你懂的
注意:这个类是 HashSet类的子类
- 这个类维护着一个运行与所有条目的双重链接列表,它具有可预知的迭代顺序
也就是说,底层是 哈希表+链表的组合
这个链表用来存储元素的存储顺序
演示代码:
package Practice;
import java.util.LinkedHashSet;
public class Demo1 {
public static void main(String[] args) {
LinkedHashSet<Integer> set = new LinkedHashSet<>();
set.add(1);
set.add(2);
set.add(3);
set.add(4);
set.add(5);
set.add(6);
//我们会发现,这里按顺序迭代出来了
for (Integer integer : set) {
System.out.println(integer);
}
}
}
4.5 可变参数
在JDK1.5之后,如果我们定义一个方法能接受读个参数,并且参数类型一致,我们就可以简化成如下形式:
修饰符 返回值类型 方法名(参数类型...形参名){ }
其实这个书写完全等价于
修饰符 返回值类型 方法名(参数类型[] 形参名){ }
- 因为其底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数,甚至可以不传递参数
package Practice;
//类型确定,但是个数不确定,就可以使用
public class Demo1 {
public static void main(String[] args) {
System.out.println(sum());
}
public static int sum(int...a){
//a相当于就是一个数组
int sum = 0;
for (int i : a) {
sum+=i;
}
return sum;
}
}
注意事项
- 一个方法的可变参数只能有一个
- 可变参数必须写在参数的末尾
第五章 collections
5.1 常用功能
部分方法如下:
static <T> boolean addAll(Collection<? super T> c, T... elements)
将所有指定元素添加到指定 collection 中。
static void shuffle(List<?> list)
使用默认随机源对指定列表进行置换。
static <T extends Comparable<? super T>> void sort(List<T> list)
根据元素的自然顺序 对指定列表按升序进行排序。
static <T> void sort(List<T> list, Comparator<? super T> c)
根据指定比较器产生的顺序对指定列表进行排序。
示例代码:
package Practice;
//类型确定,但是个数不确定,就可以使用
import java.util.ArrayList;
import java.util.Collections;
public class Demo1 {
public static void main(String[] args) {
ArrayList<String> arr = new ArrayList<>();
//添加方法
Collections.addAll(arr,"你爹","你爷爷","你妈","你儿子");
System.out.println(arr);//[你爹, 你爷爷, 你妈, 你儿子]
//随机打乱
Collections.shuffle(arr);//这个方法直接对源数组进行改变
System.out.println(arr);//[你儿子, 你爷爷, 你爹, 你妈]
//整理函数,默认按照升序规则排序,只能传list集合
Collections.sort(arr);
System.out.println(arr);//[你儿子, 你妈, 你爷爷, 你爹]
Comparator<String> aaa = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.charAt(0) - o2.charAt(0);
}
};
//这个是自定义了规则的排序
Collections.sort(arr,aaa);
System.out.println(arr);
}
}
注意
- 数组里面要是放的是自定义的类,那么那个类一定要实现Comparable接口 你妈, 你儿子]
//随机打乱
Collections.shuffle(arr);//这个方法直接对源数组进行改变
System.out.println(arr);//[你儿子, 你爷爷, 你爹, 你妈]
//整理函数,默认按照升序规则排序,只能传list集合
Collections.sort(arr);
System.out.println(arr);//[你儿子, 你妈, 你爷爷, 你爹]
Comparator<String> aaa = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.charAt(0) - o2.charAt(0);
}
};
//这个是自定义了规则的排序
Collections.sort(arr,aaa);
System.out.println(arr);}
}
**注意**
- 数组里面要是放的是自定义的类,那么那个类一定要**实现Comparable接口**
- 或者可以使用Compartor接口,相当于找一个第三方的裁判来找一下这个人