一、数据结构
1.栈结构
特点:先进后出
栈内存:先进后出。主方法最先压栈,剩余的方法随着调用就会不断的进栈。当执行完毕时,立即从栈内存消失
堆内存:当new对象的时候,对象才出现。当这个对象没有任何引用的时候,会变成垃圾。由垃圾回收器不定时的回收
栈结构只能操作一端,不是运算受限的线性表
2.队列结构
特点:先进先出
举例:排队
运算受限的线性表
能对首尾进行操作
LinkedList中的addFrist()和addLast()可以模拟出队列
3.数组结构
特点:
查询快:数组是一块连续的内存空间。而且有对应的索引。通过索引快速的定位到要查找的内容
增删慢:数组的长度是固定的,如果要对元素进行增删。则需要创建新数组来完成
4.链表结构
数据结构层面特点:
查询慢:链表的地址不是连续的,查询的时候需要一个一个的进行查找
增删快:每个元素都会记录上一个元素的地址值(双向的是互相记录地址)。如果想删除或增加一个元素,其他的元素不需要变动,只需要将对应的记录更改即可
LinkedList集合:
此集合也是有索引的。有索引但是查询慢的原因如下:
我们传入一个要查询的索引,底层先会做一个判断。
结果1:如果传入的索引要是比集合长度的中间值索引要小,从前向后查找。而且是一个一个的找
结果2:如果传入的索引要是比集合长度的中间值索引要大,从后向前查找。而且是一个一个的找
总结:
如果查询多,优先使用ArrayList
如果增删多,优先使用LinkedList
如果不确定,优先使用ArrayList
5.树结构
图解略~
二、List
1.List特点
有索引、可以存储重复元素、存取有序
ArrayList:底层是数组实现,查询快、增删慢。
|–ArrayList集合底层是数组结构,第一个数组是长度为10,如果添加的元素超过10,那么下一个就会
以1.5倍的速度去创建一个新的集合,再使用Arrays.copyOfRange(Object []original,start,end) 不包含end
/*
//这就属于多态 只能用List接口里面的方法
List<String> list = new ArrayList<>();
//欲想使用ArrayList集合中的trimToSzie()方法,那么就不许转型
// 这仅仅是为了演示一下多态的转型概念
ArrayList<String> arr = (ArrayList<String>) list;
arr.trimToSize(); //这时候就可以使用这个方法了
*/
LinkedList:底层是链表实现,查询慢、增删快。
|--可以对首尾进行操作(添加或者删除操作)比add(int index,E element) 和 remove(int index)
方法的效率要稍微高那么一点点,因为他在进行添加删除操作的时候不用去通过下标去查找
2.常用方法
void add(int index,E e); 向集合中指定索引位置去添加元素
E get(int index); 获取指定索引处的元素
E remove(int index); 删除指定索引上的元素
E set(int index,E e); 修改指定索引上的元素
3.示例代码:
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("d");
list.add("a");
//打印集合
System.out.println(list);//[a, b, c, d, a] 不是地址重写了toString
//public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
//在c和d之间添加一个itheima
list.add(3,"itheima");//[a, b, c, itheima, d, a]
System.out.println(list);
//public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
//移除元素
String removeE = list.remove(2);
System.out.println("被移除的元素:"+removeE);//被移除的元素:c
System.out.println(list);//[a, b, itheima, d, a]
//public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
//把最后一个a,替换为A
String setE = list.set(4, "A");
System.out.println("被替换的元素:"+setE);//被替换的元素:a
System.out.println(list);//[a, b, itheima, d, A]
}
}
4.LinkedList集合
特有方法:
java.util.LinkedList集合 implements List接口
LinkedList集合的特点:
1.底层是一个链表结构:查询慢,增删快
2.里边包含了大量操作首尾元素的方法
注意:使用LinkedList集合特有的方法,不能使用多态
void addFirst(E e):将指定元素插入此列表的开头。
void addLast(E e):将指定元素添加到此列表的结尾。
void push(E e):将元素推入此列表所表示的堆栈。
E getFirst():返回此列表的第一个元素。
E getLast():返回此列表的最后一个元素。
E removeFirst():移除并返回此列表的第一个元素。
E removeLast():移除并返回此列表的最后一个元素。
E pop():从此列表所表示的堆栈处弹出一个元素。
boolean isEmpty():如果列表不包含元素,则返回true。
public class Demo02LinkedList {
public static void main(String[] args) {
show03();
}
/*
- public E removeFirst():移除并返回此列表的第一个元素。
- public E removeLast():移除并返回此列表的最后一个元素。
- public E pop():从此列表所表示的堆栈处弹出一个元素。此方法相当于 removeFirst
*/
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 first = linked.removeFirst();
String first = linked.pop();
System.out.println("被移除的第一个元素:"+first);
String last = linked.removeLast();
System.out.println("被移除的最后一个元素:"+last);
System.out.println(linked);//[b]
}
/*
- public E getFirst():返回此列表的第一个元素。
- public E getLast():返回此列表的最后一个元素。
*/
private static void show02() {
//创建LinkedList集合对象
LinkedList<String> linked = new LinkedList<>();
//使用add方法往集合中添加元素
linked.add("a");
linked.add("b");
linked.add("c");
//linked.clear();//清空集合中的元素 在获取集合中的元素会抛出NoSuchElementException
//public boolean isEmpty():如果列表不包含元素,则返回true。
if(!linked.isEmpty()){
String first = linked.getFirst();
System.out.println(first);//a
String last = linked.getLast();
System.out.println(last);//c
}
}
/*
- public void addFirst(E e):将指定元素插入此列表的开头。
- public void addLast(E e):将指定元素添加到此列表的结尾。
- public void push(E e):将元素推入此列表所表示的堆栈。此方法等效于 addFirst(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]
//public void addFirst(E e):将指定元素插入此列表的开头。
//linked.addFirst("www");
linked.push("www");
System.out.println(linked);//[www, a, b, c]
//public void addLast(E e):将指定元素添加到此列表的结尾。此方法等效于 add()
linked.addLast("com");
System.out.println(linked);//[www, a, b, c, com]
}
}
5.Vector集合
ArrayList和Vector集合的区别
相同点:底层都是数组实现的
不同点:ArrayList是JDK1.2版本出现的。Vector是JDK1.0版本出现的
ArrayList是线程不安全的,效率较高,但是数据不安全
Vector是线程安全的,效率较低,但是数据安全
示例代码:
public class Demo01 {
public static void main(String[] args) {
Vector<String> v = new Vector<>();
v.addElement("abc");
v.addElement("bcd");
v.addElement("def");
for (String s : v) {
System.out.println(s);
}
System.out.println("================");
Iterator<String> it = v.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
System.out.println("================");
Enumeration<String> e = v.elements();
while(e.hasMoreElements()) {
System.out.println(e.nextElement());
}
}
}
三、Set
1.Set集合特点
无索引、不能存储重复元素、存取无序
HashSet:底层是哈希算法(红黑树),无索引、不能存储重复元素、存取无序
LinkedHashSet:底层是哈希算法+链表双实现,无索引、不能存储重复元素。可以保证存取顺序
|–LinkedHashSet是有序的
注意事项:
???Set集合遍历的时候不能使用for循环(因为没有下标,无法对其遍历)
|--增强for循环
|--迭代器
???红黑树(平衡二叉树/排序树)查询速度相当快 -->桶结构存储
2.示例代码:
public class Demo01Set {
public static void main(String[] args) {
Set<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 无序,没有重复的
}
//使用增强for遍历set集合
System.out.println("-----------------");
for (Integer i : set) {
System.out.println(i);
}
}
}
3.Set集合不重复的原理
第一种情况:哈希值不同,直接存储
第二种情况:哈希值相同,但是equals方法不同。以桶结构存储
第三种情况:哈希值相同,但是equals方法也相同。不存储了
4.HashSet存储自定义类型数据
此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。
它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
//Person类
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@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;
}
}
//测试类
public class Demo03HashSetSavePerson {
public static void main(String[] args) {
//创建HashSet集合存储Person
HashSet<Person> set = new HashSet<>();
Person p1 = new Person("小美女",18);
Person p2 = new Person("小美女",18);
Person p3 = new Person("小美女",19);
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);
}
}
5.LinkedHashSet集合的使用
public class Demo04LinkedHashSet {
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] 有序,不允许重复
}
}
四、可变参数
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);
method("abc",5.5,10,1,2,3,4);
}
/*
可变参数的注意事项
1.一个方法的参数列表,只能有一个可变参数
2.如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
*/
/*public static void method(int...a,String...b){
}*/
/*public static void method(String b,double c,int d,int...a){
}*/
//可变参数的特殊(终极)写法
public static void method(Object...obj){
}
/*
定义计算(0-n)整数和的方法
已知:计算整数的和,数据类型已经确定int
但是参数的个数不确定,不知道要计算几个整数的和,就可以使用可变参数
add(); 就会创建一个长度为0的数组, new int[0]
add(10); 就会创建一个长度为1的数组,存储传递来过的参数 new int[]{10};
add(10,20); 就会创建一个长度为2的数组,存储传递来过的参数 new int[]{10,20};
add(10,20,30,40,50,60,70,80,90,100); 就会创建一个长度为2的数组,存储传递来过的参数 new int[]{10,20,30,40,50,60,70,80,90,100};
*/
public static int add(int...arr){
//System.out.println(arr);//[I@2ac1fdc4 底层是一个数组
//System.out.println(arr.length);//0,1,2,10
//定义一个初始化的变量,记录累加求和
int sum = 0;
//遍历数组,获取数组中的每一个元素
for (int i : arr) {
//累加求和
sum += i;
}
//把求和结果返回
return sum;
}
}
五、集合的工具类
1.Collections工具类
- public static boolean addAll(Collection c, T… elements):往集合中添加一些元素。
- public static void shuffle(List
public class Demo01Collections {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//public static <T> boolean addAll(Collection<T> c, T... elements):往集合中添加一些元素。
Collections.addAll(list,"a","b","c","d","e");
System.out.println(list);//[a, b, c, d, e]
//public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序。
Collections.shuffle(list);
System.out.println(list);//[b, d, c, a, e], [b, d, c, a, e]
}
}
- public static <T> void sort(List<T> list):将集合中元素按照默认规则排序。
示例代码:
//Person类
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@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 o) {
//return 0;//认为元素都是相同的
//自定义比较的规则,比较两个人的年龄(this,参数Person)
//return this.getAge() - o.getAge();//年龄升序排序
return o.getAge() - this.getAge();//年龄降序排序
}
}
//测试类
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=20}, Person{name='王五', age=15}]
Collections.sort(list03);
System.out.println(list03);
}
}
- public static <T> void sort(List<T> list,Comparator<? super T> ):将集合中元素按照指定规则排序。
示例代码:
//学生类
public class Student {
private String name;
private int age;
private int score;
public Student() {
}
public Student(String name, int age, int score) {
this.name = name;
this.age = age;
this.score = score;
}
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 int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
}
//测试类
public class Test02 {
public static void main(String[] args) {
ArrayList<Student> list = new ArrayList<>();
Student s1 = new Student("张三",23,88);
Student s2 = new Student("李四",22,85);
Student s3 = new Student("王五",25,95);
Student s4 = new Student("赵六",22,87);
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
System.out.println(list);
//按照年龄的升序为主要条件
//如果年龄一样的情况,再按照成绩的降序排序
Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int result = s1.getAge() - s2.getAge(); // 按照年龄的升序排序
//如果年龄相同,再按照成绩的降序排序
return (result == 0) ? s2.getScore() - s1.getScore() : result;
}
});
//按照年龄的升序排序
// [Student{name='李四', age=22, score=85}, Student{name='赵六', age=22, score=87}, Student{name='张三', age=23, score=88}, Student{name='王五', age=25, score=95}]
/*Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int result = s1.getAge() - s2.getAge();
return result;
}
});*/
System.out.println(list);
}
}
补充:
/*下面我想对一个ArrayList集合进行降序排序(本来默认的都是升序排序)*/
ArrayList<Integer> list = new ArrayList<>();
list.add(1);
list.add(5);
list.add(3);
list.add(7);
list.add(4);
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1; //重写之后的方法进行的是降序排序
}
});
System.out.println(list);
2.补充的工具类方法
public class Demo04 {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
list.add("ee");
//int binarySearch(List list, T key) 使用二分查找法获取元素在集合中出现的索引位置 如果查找的元素不存在,则返回此元素的-插入点-1
int index = Collections.binarySearch(list,"cc");
System.out.println(index);
//boolean replaceAll(List<T> list, T oldVal, T newVal) 使用新元素对集合中的老元素进行替换
Collections.replaceAll(list,"dd","kk");
System.out.println(list);
//void reverse(List<?> list) 反转集合
Collections.reverse(list);
System.out.println(list);
//void swap(List<?> list, int i, int j) 将两个索引位置上的元素交换
Collections.swap(list,0,1);
System.out.println(list);
//void copy(List dest, List src) 将源集合复制到目标集合中.目标集合长度必须大于等于源集合的长度
/* ArrayList<String> dest = new ArrayList<>();
dest.add("a");
dest.add("b");
dest.add("c");
dest.add("d");
dest.add("e");
dest.add("f");
Collections.copy(dest,list);
System.out.println(dest);*/
}
}