目录
[TOC]
第一章:数据结构基础
1.1-什么是数据结构
数据结构就是计算机存储、组织数据的方式 。
指的是相互之间存在着特定关系的一种或多种的数据元素集合。
1.2-为什么要学习数据结构
通常情况下,精心选择合适的数据结构可以带来更高的运行或存储的效率。
数据结构往往同高效的检索算法和索引技术有关。
1.3-数据结构-栈
栈结构介绍
- 栈:栈(stack)又名堆栈,是一种运算受限的线性表。
- 受限:限定仅在表尾进行插入和删除操作的线性表(这一端被称为栈顶,另一端称为栈底)
特性
特性:先进后出
1.4-数据结构-队列
队列介绍
- 队列:是一种受限的特殊线性表。
- 受限:只允许在表的前端(队头)进行删除操作,后端(队尾)进行插入操作。
队列特性
特性:先进先出
1.5-数据结构-数组
数组介绍
数组:一组有序的(索引有序并且从0开始)类型相同的长度固定的元素集合。
特性
- 元素有序
- 元素同类型
- 长度固定
应用效果
-
查询快
。- 从数组索引0开始查找,根据指定位置的偏移量可快速获取数据。
-
增删慢
。- 数组的长度是固定的,若删除或增加一格元素,则会先创建一个新的数组,再把原数组的数据根据操作复制到新数组中。
1.6-数据结构-链表
链表介绍
-
单向链表:单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
- 双向链表:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
链表特性
- 由一系列结点(链表中的每一个元素称为结点)组成。
- 结点可以在运行时动态生成。
- 每个结点包括两个部分(单链表)
- 一个是存储数据元素的数据域
- 另一个是存储下一个结点地址的指针域。
应用效果
-
查询慢
:链表的地址不是连续的,每次查找都得从头开始查找。 -
增删快
:增删操作不会影响链表的整体结构。
1.7-数据结构-红黑树
介绍
红黑树(Red Black Tree) 是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。
特性
-
查询速度快
- 在进行插入和删除操作时通过特定操作保持二叉查找树的平衡,从而获得较高的查找性能。
第二章:泛型介绍
2.1-什么是泛型
泛型,未知的类型,可以在类或方法中预支地使用未知的类型。
2.2-泛型的好处
可以避免类型转换的麻烦。
2.3-定义和使用含有泛型的类
定义
修饰符 class 类名<代表泛型的变量> { }
使用
在创建对象的使用。也就是在创建对象时确定泛型的类型。
public class ArrayList<E> {
public boolean add(E e){ }
...
}
public class MainDemo{
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("张三");
}
}
2.4-定义和使用含有泛型的方法
定义
修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
使用
public static void main(String[] args) {
methon1("张三");
}
public static <M> void methon1(M m){
System.out.println(m);
}
2.5-定义和使用含有泛型的接口
定义
修饰符 interface接口名<代表泛型的变量>
使用
public interface TestInterface<T> {
public abstract void show(T t);
}
public class<T> TestImpl implements TestInterface<T> {
@Override
public T void show(T o) {
System.out.println(o);
}
}
public class Main01 {
public static void main(String[] args) {
TestImpl<String> t = new TestImpl<>();
t.show("我的信息");
}
}
第三章:单列集合-Collection系列
3.1-集合介绍
-
定义:在Java中,集合是一种可以存储多个数据的容器。
-
代码:
ArrayList<String> list = new ArrayList<>(); list.add("张三"); list.add("王五"); list.add("赵六"); System.out.println(list); // [张三, 王五, 赵六]
3.2-集合和数组的区别
-
区别:数组的长度是固定的,集合的长度是可变的。
-
代码:
String[]strs = new String[2]; strs[0] = "张三"; strs[1] = "李四"; // strs[2] = "赵六"; // 运行时报错java.lang.ArrayIndexOutOfBoundsException ArrayList<String> list = new ArrayList<>(); System.out.println(list.size()); // 0 list.add("张三"); list.add("王五"); list.add("赵六"); System.out.println(list.size()); // 3
3.3-集合框架Collection
10.jpg概述
- 单列集合类的根接口
- 有两个子接口
- java.util.List;特点是:内容可重复,有序
- java.util.Set; 特点是:内容不可重复,无序
- 定义了单例集合最共性的方法。
通用方法
方法:
-
public boolean add(E e)
: 把给定的对象添加到当前集合中 。 -
public void clear()
:清空集合中所有的元素。 -
public boolean remove(E e)
: 把给定的对象在当前集合中删除。 -
public boolean contains(E e)
: 判断当前集合中是否包含给定的对象。 -
public boolean isEmpty()
: 判断当前集合是否为空。 -
public int size()
: 返回集合中元素的个数。 -
public Object[] toArray()
: 把集合中的元素,存储到数组中。
代码:
List<String> list = new ArrayList<>();
// 添加元素
list.add("张三");
list.add("李四");
System.out.println(list);
// 移除元素
list.remove("张三");
System.out.println(list);
// 判断集合中是否包含某个元素
boolean isHas = list.contains("张三");
System.out.println(isHas); // false
// 判断当前集合是否为空
boolean isEmpty = list.isEmpty();
System.out.println(isEmpty);
// 清空元素
list.clear();
System.out.println(list);
// 集合的长度
System.out.println(list.size());
// 集合中的元素存储到一个数组中
Object[]s = list.toArray();
遍历集合
-
Iterator方式
-
介绍:Iterator,是一个迭代器接口。Collection中的成员方法iterator()被调用后,会返回一个Iterator对象。利用这个对象可以实现遍历集合。如何遍历呢?在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
-
Iterator对象的成员方法:
- hasNext(); 检测集合中是否存在下一个元素
- next(); 找到并获取下一个元素
-
迭代器的原理:在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
-
代码:
List<String> list = new ArrayList<>(); list.add("张三"); list.add("李四"); list.add("王五"); // 得到一个迭代器对象 Iterator<String> it = list.iterator(); while (it.hasNext()) { String str = it.next(); System.out.println(str); }
-
-
增强for方式
-
介绍:增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删操作。
-
使用格式
for(元素的数据类型 变量 : Collection集合or数组){ //写操作代码 }
-
代码:
for (String name:list) { System.out.println(name); }
-
3.4-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 = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
// public void add(int index, E element) : 将指定的元素,添加到该集合中的指定位置上。
list.add(1,"d");
System.out.println(list); // [a, d, b, c]
// public E get(int index) :返回集合中指定位置的元素。
System.out.println(list.get(2)); // b
// public E remove(int index) : 移除列表中指定位置的元素, 返回的是被移除的元素。
list.remove(1);
System.out.println(list); // [a, b, c]
// public E set(int index, E element) :用指定元素替换集合中指定位置的元素,返回值的更新前的元素
list.set(1,"B");
System.out.println(list); // [a, B, c]
List集合实现类-ArrayList
java.util.ArrayList 集合数据存储的结构是数组结构。元素增删慢,查找快,用于日常开发中使用最多的功能为 查询数据、遍历数据,所以 ArrayList 是最常用的集合。
许多程序员开发时非常随意地使用ArrayList完成任何需求,并不严谨,这种用法是不提倡的。
List集合实现类-LinkedList
java.util.LinkedList 集合数据存储的结构是链表结构。方便元素添加、删除的集合。
常用方法:
-
public void addFirst(E e)
:将指定元素插入此列表的开头。 -
public void addLast(E e)
:将指定元素添加到此列表的结尾。 -
public E getFirst()
:返回此列表的第一个元素。 -
public E getLast()
:返回此列表的最后一个元素。 -
public E removeFirst()
:移除并返回此列表的第一个元素。 -
public E removeLast()
:移除并返回此列表的最后一个元素。 -
public E pop()
:从此列表所表示的堆栈处弹出一个元素。 -
public void push(E e)
:将元素推入此列表所表示的堆栈。 -
public boolean isEmpty()
:如果列表不包含元素,则返回true。
代码:
LinkedList list = new LinkedList();
list.add("a");
list.add("b");
// public void addFirst(E e) :将指定元素插入此列表的开头。
list.addFirst("A");
// public void addLast(E e) :将指定元素添加到此列表的结尾。
list.addLast("B");
System.out.println(list); // [A, a, b, B]
// public E getFirst() :返回此列表的第一个元素。
System.out.println(list.getFirst()); // A
// public E getLast() :返回此列表的最后一个元素。
System.out.println(list.getLast()); // B
// public E removeFirst() :移除并返回此列表的第一个元素。
list.removeFirst();
// public E removeLast() :移除并返回此列表的最后一个元素。
list.removeLast();
System.out.println(list); //[a, b]
// public E pop() :从此列表所表示的堆栈处弹出一个元素。
list.pop();
System.out.println(list); // [b]
// public void push(E e) :将元素推入此列表所表示的堆栈。
list.push("a");
System.out.println(list); // [a, b]
// public boolean isEmpty() :如果列表不包含元素,则返回true。
System.out.println(list.isEmpty()); // false
3.5-Set集合
概述
- 继承了Collectin集合
- 没有扩充方法
- 与List集合不同的是会
保证集合中元素的唯一性
。
HashSet
介绍:
-
集合中的元素
存取是无序的
-
集合中的元素是
不重复的
-
HashSet 是
根据对象的哈希值来确定元素在集合中的存储位置
,因此具有良好的存取和查找性能。保证元素唯一性
的方式依赖于:hashCode
与equals
方法。 -
代码:
Set set = new HashSet(); set.add("张三"); set.add("李四"); set.add("李四"); set.add("王五"); set.add("赵六"); System.out.println(set); // [李四, 张三, 王五, 赵六]
哈希值:
-
一个十进制的逻辑地址。
-
所有的对象都继承里Object中的HashCode方法
-
代码:
System.out.println("a".hashCode()); // 97 System.out.println("b".hashCode()); // 98 System.out.println("张三".hashCode()); // 774889 System.out.println("李四".hashCode()); // 842061 int[]arr1={1,2,3}; System.out.println(arr1.hashCode()); //1355531311
存储结构:数组+链表/红黑树
,在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。 但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找 时间。
总而言之,JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一, 其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一, 就必须复写hashCode和equals方法建立属于当前对象的比较方式。
代码:要求自定义人物类型(含有姓名、年龄),用HashSet集合存储,若对象的姓名和年龄一致则在集合中不允许重复
/*人物类*/
public class People {
private String name;
private int age;
public People(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;
People people = (People) o;
return age == people.age &&
name.equals(people.name);
}
@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 class Main {
public static void main(String[] args) {
People p1 = new People("张三",10);
People p2 = new People("李四",12);
People p4 = new People("李四",12);
People p3 = new People("王五",10);
HashSet set = new HashSet();
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
System.out.println(set.size()); // 3
}
}
LinkedHashSet
-
组织结构:哈希表(数组+链表/红黑树) + 链表(记录存取顺序)
-
特点:
- 元素唯一性
- 元素存取有序。
-
代码:
LinkedHashSet set = new LinkedHashSet(); set.add("张三"); set.add("李四"); set.add("李四"); set.add("王五"); set.add("赵六"); System.out.println(set); // [张三, 李四, 王五, 赵六]
其他扩展-可变参数
-
格式:
修饰符 返回值类型 方法名(参数类型... 形参名){ } 等价于 修饰符 返回值类型 方法名(参数类型[]形参名){ }
-
代码:
public static void main(String[] args) { System.out.println(add(1,2,3)); // 6 System.out.println(add(1,200,300,400)); // 901 } public static int add(int...num) { int sum = 0; for (int i = 0; i < num.length; i++) { sum += num[i]; } return sum; }
-
原理:在编译成class文件时,源代码中的可变参数会自动变成数组。
-
注意事项:
- 可变参数类型要一致
- 可变参数要放在参数列表最后
3.6 Collections
介绍
java.utils.Collections 是集合工具类,用来对集合进行操作 。常用的方法如下:
-
public static <T> boolean addAll(Collection<T> c, T... elements)
:往集合中添加一些元素。 -
public static void shuffle(List<?> list)
打乱顺序 :打乱集合顺序。 -
public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序。 -
public static <T> void sort(List<T> list,Comparator<? super T> )
:将集合中元素按照指定规则排序。
代码
ArrayList<Integer> list = new ArrayList<>();
//public static <T> boolean addAll(Collection<T> c, T... elements) :往集合中添加一些元素。
Collections.addAll(list, 1, 3, 4, 5, 6, 8, 7);
System.out.println(list); // [1, 3, 4, 5, 6, 8, 7]
//public static void shuffle(List<?> list) 打乱顺序 :打乱集合顺序。
Collections.shuffle(list);
System.out.println(list); // 随机顺序[5, 4, 6, 3, 7, 1, 8]
//public static <T> void sort(List<T> list) :将集合中元素按照默认规则排序。
Collections.sort(list);
System.out.println(list); // 默认升序[1, 3, 4, 5, 6, 7, 8]
//public static <T> void sort(List<T> list,Comparator<? super T> ) :将集合中元素按照指定规则排序。
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
System.out.println(list);
注意事项
若要对自定义对象进行排序时,使用 sort(List<T> list)
时,自定义类型需要实现Comparable接口,并且要重新CompareTo方法
public class People implements Comparable<People> {
private String name;
private int age;
public People(String name, int age) {
this.name = name;
this.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(People o) {
return this.age - o.age; // 升序
// return o.age-this.age; 降序
}
}
第四章:双列集合-Map系列
4.1-Map集合介绍
- Map集合是一个存储数据的容器。
- Map集合存储数据的方式是键值对(key/value)。
- key键不可以重复(若重复设置,则会覆盖原有key对应的值)。
- value值可以重复。
- Map集合的底层数据结构是哈希表(数组+链表/红黑树)。
4.2-Map集合常用子类
HashMap
- 是Map集合的一个子类
- 底层数据结构是哈希表
- 键不可以重复(键对应的类型需要重写了hashCode()和equals方法()),值可以重复。
- 存取是无序的(存取顺序可能不一致)
LinkedHashMap
- 是HashMap集合的一个子类
- 底层数据结构是哈希表+链表(记录存取顺序)
- 键不可以重复(键对应的类型需要重写了hashCode()和equals方法()),值可以重复。
- 存取是有序的(存取的顺序一定是一致的)
注意事项
Map接口中的集合都有两个泛型变量,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量的数 据类型可以相同,也可以不同
public interface Map<K, V>{}
4.3-Map集合常用方法
方法
-
public V put(K key, V value)
: 把指定的键与指定的值添加到Map集合中。 -
public V remove(Object key)
: 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。 -
public V get(Object key)
根据指定的键,在Map集合中获取对应的值。 -
public Set<K> keySet()
: 获取Map集合中所有的键,存储到Set集合中。 -
public Set<Map.Entry<K,V>> entrySet()
: 获取到Map集合中所有的键值对对象的集合(Set集合)。
代码
// 创建HashMap对象
HashMap<String,String> hash = new HashMap<>();
// 【添加数据-public V put(K key, V value)】
hash.put("郭靖","华筝");
hash.put("郭靖","黄蓉"); // 会覆盖之前重复的键值对
hash.put("杨过","小龙女");
hash.put("张无忌","赵敏");
hash.put("宋青书","周芷若");
System.out.println(hash); // {杨过=小龙女, 宋青书=周芷若, 郭靖=黄蓉, 张无忌=赵敏}
// 【移除数据-public V remove(Object key)】
hash.remove("宋青书");
System.out.println(hash); // {杨过=小龙女, 郭靖=黄蓉, 张无忌=赵敏}
// 【根据指定的键获取对应的值-public V get(Object key)】
String value = hash.get("郭靖");
System.out.println(value); // 黄蓉
// 【获取Map集合中所有的键存储到Set集合中-public Set<K> keySet()】
Set<String> set = hash.keySet();
Iterator<String> iterator = set.iterator();
while ((iterator.hasNext())){
String key = iterator.next();
System.out.println(key + "-" + hash.get(key));
}
// 【获取Map集合中的Entry对象-public Set<Map.Entry<K,V>> entrySet()】
// Map集合中存储了一组Entry对象,entry对象包装了每一对key/value
// Entry对象可以通过getKey()方法获取键,通过getValue方法获取对应的值
Set<Map.Entry<String,String>> set2 = hash.entrySet();
for (Map.Entry<String,String> entry:set2) {
System.out.println(entry.getKey() + '|'+entry.getValue());
}
4.4-Map集合中定义自定义类型的键值对
对应自定义类型的键的类型中需要重新hashCode和equals方法
//【执行类】
public class Main {
public static void main(String[] args) {
// 存储一组学生信息,要求集合中不允许出现同名同年龄的键
HashMap<Student,Integer> hash = new HashMap<>();
hash.put(new Student("张三",18),10010);
hash.put(new Student("张三",18),10086);
hash.put(new Student("李四",17),10010);
hash.put(new Student("王五",17),10010);
System.out.println(hash.size()); // 3个
}
}
//【学生类】
public class Student {
private String name;
private int age;
public Student() {}
public Student(String name, int age) {
this.name = name;
this.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 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);
}
}
4.5-LinkedHashMap
-
介绍:是HashMap的子类,存取数据是有序的。
-
代码:
LinkedHashMap<String,String> hash = new LinkedHashMap<>(); hash.put("郭靖","黄蓉"); hash.put("杨过","小龙女"); hash.put("张无忌","赵敏"); hash.put("宋青书","周芷若"); System.out.println(hash);//{郭靖=黄蓉, 杨过=小龙女, 张无忌=赵敏, 宋青书=周芷若}
4.6-HashTable
-
HashTable集合
- 底层是线程是安全的,单线程,执行速度慢
- 底层数据结构是哈希表
- 之前学习的集合可以存储null键和null值,但是HashTable不可以
-
代码:
HashMap<String,Integer> map = new HashMap<>(); map.put(null,1); map.put("a",null); System.out.println(map); Hashtable<String,Integer> table = new Hashtable<>(); table.put(null,1); // 报错NullPointerException table.put("a",null); System.out.println(table);
4.7-JDK9对集合添加的优化
-
在创建少量元素的集合时,使用JDK9中提供的静态方法of添加更加合适
-
注意事项:
- of方法只能被接口List、Set、Map接口调用,不能用子类或实现类调用。
- of方法初始化后的集合不能更改。
-
代码:
List<String> list = List.of("张三","李四","王五","赵六"); Set<String> set = Set.of("张三","李四","王五","赵六"); Map<String,Integer> map = Map.of("张三",10,"李四",12); System.out.println(list); // [张三, 李四, 王五, 赵六] System.out.println(set); // [李四, 赵六, 张三, 王五] System.out.println(map); // {张三=10, 李四=12}
网友评论