什么是算法和数据结构
1.算法
【1】可以解决具体问题 eg: 1+2+3+4+。。。+100 --> 5050
解题流程 = 算法
【2】有设计解决的具体流程
算法1:1+2=3 , 3+3=6 .。。。 加到100 --> 5050
算法2:(1+100)*50/2 = 5050
【3】有评价这个算法的具体指标 --> 时间复杂度 空间复杂度 (从数学角度考虑)
2.数据结构:就是在计算机的缓存,内存,硬盘,如何组织管理数据的。
重点在结构上,按照什么结构来组织管理我们的数据
数据结构分为:
【1】逻辑结构: --> 思想上的结构 --> 线性表(数组,链表) , 图, 树,栈,队列
【2】物理结构: --> 真实的结构 --> 紧密结构(顺序结构) ,跳转结构(链式结构)
物理结构: 紧密结构(顺序结构) ,跳转结构(链式结构)
以线性表为例
线性表的特点:
n个类型相同的数据元素的有限序列
【1】相同数据类型
【2】序列(顺序性)
【3】有限
逻辑结构和物理结构的关系
线性表逻辑结构,对应的真实结构如果是紧密结构 --> 典型:数组
线性表逻辑结构,对应的真实结构如果是跳转结构 --> 典型:链表
优点:添加,删除 元素 效率高
缺点:查询元素效率低
【1】数组,集合 都是对多个数据进行存储操作的,简称为容器
ps: 这里的存储指的是内存层面的存储。而不是持久化存储
【2】数组特点:
1.数组一旦指定了长度,那么长度就被确定了,不可以更改
int[] arr = new int[6]
2.数组一旦声明了类型以后,数组中只能存放这个类型的数据。数组中只能存放同一种类型的数据
【3】数组的缺点:
1.数组一旦确定长度,不可修改
2.删除元素,或增加元素,效率低
3.数组中实际元素的数量是没有办法获取的,没有提供对应的方法或属性来获取
4.数组存储:有序,可重复,对于无序的,不可重复的,数组不能满足要求
【4】正因为上面的缺点,引入了一个新的存储数据的结构 --> 集合
public class Test01 {
public static void main(String[] args) {
Collection col = new ArrayList();
col.add("aaa");
col.add(1);
col.add(true);
col.add(9.9);
col.add('a');
List intList = Arrays.asList(new Integer[]{11, 15, 14, 41});
// addAll
col.addAll(intList);
// clear() 清空集合
col.clear();
// size()
col.size();
// isEmpty
col.isEmpty();
// remove()
boolean isRemove = col.remove(1);
// equals
List intList1 = Arrays.asList(new Integer[]{1, 2, 3});
List intList2 = Arrays.asList(new Integer[]{1, 2, 3});
boolean equals = intList1.equals(intList2);
// containsAll(Collection> c) contains(Object o)
List intList3 = Arrays.asList(new Integer[]{1, 2, 3, 4});
List intList4 = Arrays.asList(new Integer[]{1, 2, 3});
boolean contains = intList3.containsAll(intList4);
System.out.println(contains);
}
}
集合遍历
public class Test02 {
public static void main(String[] args) {
Collection col = Arrays.asList(new Integer[]{1, 2, 3, 4, 5, 6});
// 对集合进行遍历
// 方式1.普通for循环 无法遍历
// 方式2. 增强for循环
for (Integer integer : col) {
System.out.println(integer);
}
// 方式3. iterator()
Iterator iterator = col.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
List接口的常用方法
public class Test03 {
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(3,1);
//set(int index, E element) 修改指定索引位置的元素
list.set(3,2);
// remove(int index)
// 在集合中存入的是Integer类型数据的时候,调用remove()方法调用的是:remove(int index)
list.remove(3);
// remove(Object o)
list.add("abc");
list.remove("abc");
// get(int index) 通过索引查看元素
Object o = list.get(0);
// List集合遍历
// 方式一:普通for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
// 方式二:增强for循环
for (Object o1 : list) {
System.out.println(o1);
}
// 方式三:iterator
Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
ArrayList源码
jdk1.7
【1】底层源码重要属性
在jdk1.7中:在调用构造器的时候给底层数组elementData初始化,数组初始化长度为10
内存:
调用add方法
当数组中的10个位置都满了的时候就开始进行扩容,扩容长度为原数组的1.5倍
jdk1.8ArrayList底层源码
【1】jdk1.8底层依旧是Object类型数组,size:数组中的有效长度
【2】ArrayList al = new ArrayList();调用空构造器
【3】add方法
【1】底层Object数组,int类型属性表示数组中的有效长度
【2】Vector v= new Vector(); 调用构造器
【3】 add方法
底层为链表(双向链表)
package com.jf.test02;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class Test {
public static void main(String[] args) {
LinkedList list = new LinkedList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("a");
list.add("b");
list.add("c");
System.out.println(list); // linkedList可以添加重复数据
list.addFirst("d");
list.addLast("d");
System.out.println(list);
list.offer("ee");
list.offerFirst("haha");
list.offerLast("ff");
System.out.println(list);
System.out.println(list.poll()); // 删除头部元素 并返回对应元素
System.out.println(list.pollFirst());
System.out.println(list.pollLast()); // 删除尾部元素 并返回对应元素
System.out.println(list);
//list.clear();
System.out.println(list);
//System.out.println(list.pollFirst());
//System.out.println(list.removeFirst()); // 报错 Exception in thread "main" java.util.NoSuchElementException
System.out.println(list.poll());
//集合的遍历
System.out.println("-------------------------------------------------");
// 普通for循环
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
System.out.println("-------------------------------------------------");
// 增强for循环
for (String s : list) {
System.out.println(s);
}
System.out.println("-------------------------------------------------");
// 迭代器
Iterator iterator = list.iterator();
while (iterator.hasNext()){
String next = iterator.next();
System.out.println(next);
}
// 迭代器另一种写法,节省内存
for(Iterator iterator1 = list.iterator();iterator1.hasNext();){
System.out.println(iterator1.next());
}
}
}
模拟LinkedList底层代码
抽象节点 Node
public class Node {
// 上一个元素的地址
private Node pre;
// 当前存入的元素
private Object obj;
// 下一个元素的地址
private Node next;
@Override
public String toString() {
return "Node{" +
"pre=" + pre +
", obj=" + obj +
", next=" + next +
'}';
}
public Node getPre() {
return pre;
}
public void setPre(Node pre) {
this.pre = pre;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Node getNext() {
return next;
}
public void setNext(Node next) {
this.next = next;
}
}
抽象链表 MyLinkedList
public class MyLinkedList {
// 当前链中的首节点
Node first;
// 当前链中的尾节点
Node last;
// 当前链中的元素个数
int count = 0;
public MyLinkedList() {
}
public void add(Object o ){
if(first == null){ // 证明添加的元素是第一个节点
Node n = new Node(); // 将添加的元素封装为一个Node对象
n.setPre(null);
n.setObj(o);
n.setNext(null);
first = n;
last = n;
}else{
Node n = new Node(); // 证明链表中已经存在元素
n.setPre(last); // 节点n的上一个节点一定是当前链中的最后一个节点last.
n.setObj(o);
n.setNext(null);// 节点n的下一个节点为null 当前添加的节点就是最新的节点,后面在没有元素
last.setNext(n); // 当前链中的最后一个节点的下一个元素要指向n
last = n; // 当前链中的最后一个节点要变为最新的节点n
}
count++;
}
public int getSize(){
return count;
}
public Object getElement(int index){
// 获取链表的头元素
Node n = first;
for (int i = 0; i < index; i++) {
n = n.getNext();
}
return n.getObj();
}
public String toString(){
Node n = first;
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("[");
stringBuffer.append(n.getObj());
stringBuffer.append(",");
for (int i = 0; i < count -1; i++) {
Node next = n.getNext();
stringBuffer.append(next.getObj());
stringBuffer.append(",");
n = next;
}
stringBuffer.append("]");
return stringBuffer.toString();
}
@Test
public void test1(){
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.add("aa");
myLinkedList.add("bb");
myLinkedList.add("cc");
System.out.println(myLinkedList.getSize());
System.out.println(myLinkedList.getElement(1));
System.out.println(myLinkedList.toString());
}
}
迭代器
【1】Iterable接口 与 iterator方法 与 Iterator接口的关系
【2】hasNext() , next()具体实现
【3】增强for循环,也是通过迭代器实现的
ListIterator
public class Test05 {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
list.add("ee");
// 在“cc”之后添加一个字符串“kk”
Iterator iterator = list.iterator();
while(iterator.hasNext()){
if("cc".equals(iterator.next())){
list.add("ff");
}
}
}
}
并发修改异常: 迭代的同时对集合进行添加操作 引发异常
引入新迭代器: ListIterator
public class Test05 {
public static void main(String[] args) {
ArrayList list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
list.add("ee");
// 在“cc”之后添加一个字符串“kk”
ListIterator it = list.listIterator();
while(it.hasNext()){
if("cc".equals(it.next())){
it.add("ff");
}
}
System.out.println(list);
}
}
Set接口
HashSet实现类
【1】普通的引用数据类型
public class Test06 {
public static void main(String[] args) {
HashSet hashSet = new HashSet<>();
hashSet.add(19);
hashSet.add(5);
hashSet.add(19);
hashSet.add(20);
hashSet.add(41);
hashSet.add(0);
int size = hashSet.size(); // 唯一 无序
System.out.println(size); // 5
System.out.println(hashSet); // [0, 19, 20, 5, 41]
}
}
【2】自定义引用数据类型
ps: 并不满足唯一,无序特点
public class TestStudent {
public static void main(String[] args) {
HashSet hashSet = new HashSet<>();
hashSet.add(new Student(19,"lili"));
hashSet.add(new Student(20,"lulu"));
hashSet.add(new Student(18,"feifei"));
hashSet.add(new Student(19,"lili"));
hashSet.add(new Student(10,"nana"));
System.out.println(hashSet.size()); // 5
System.out.println(hashSet);
// 并不满足唯一无序特点
// [Student{age=18, name='feifei'}, Student{age=10, name='nana'}, Student{age=20, name='lulu'}, Student{age=19, name='lili'}, Student{age=19, name='lili'}]
}
}
【3】HashSet原理图:(简要原理图)
LinkedHashSet,就是在HashSet的基础上,多了一个总的链表,这个总链表将放入的元素串在一起,方便有序的遍历
public class TestStudent {
public static void main(String[] args) {
LinkedHashSet hashSet = new LinkedHashSet<>();
hashSet.add(new Student(19,"lili"));
hashSet.add(new Student(20,"lulu"));
hashSet.add(new Student(18,"feifei"));
hashSet.add(new Student(19,"lili"));
hashSet.add(new Student(10,"nana"));
System.out.println(hashSet.size());
System.out.println(hashSet);
}
}
比较器的使用
【1】以int类型为案例
比较思路:将比较的数据做差,然后返回一个int类型的数据,将这个int类型的数据按照 =0 >0 <0 进行比较
int a = 10; int b = 20; System.out.println(a-b);
【2】比较String类型的数据:
String类实现了Comparable接口,这个接口中有一个抽象方法compareTo,String类中重写这个方法即可
String str1 = "A";
String str2 = "B";
int i = str1.compareTo(str2);
System.out.println(i);
【3】比较自定义数据类型
1.内部比较器
public class Student implements Comparable{ private int age; private double height; private String name; public Student(int age, double height, String name) { this.age = age; this.height = height; this.name = name; } @Override public String toString() { return "Student{" + "age=" + age + ", height=" + height + ", name='" + name + ''' + '}'; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int compareTo(Student o) { // 按照年龄进行比较 //return this.getAge() - o.getAge(); // 比较身高 return ((Double)this.getHeight()).compareTo((Double)o.getHeight()); } }
public class Test01 {
public static void main(String[] args) {
Student s1 = new Student(10, 160, "lili");
Student s2 = new Student(14, 170.5, "nana");
int res = s1.compareTo(s2);
System.out.println(res);
}
}
2.外部比较器
public class Student {
private int age;
private Double height;
private String name;
public Student() {
}
public Student(int age, Double height, String name) {
this.age = age;
this.height = height;
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", height=" + height +
", name='" + name + ''' +
'}';
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Double getHeight() {
return height;
}
public void setHeight(Double height) {
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class BiJiao01 implements Comparator{
@Override
public int compare(Student o1, Student o2) {
// 比较年龄
return o1.getAge() - o2.getAge();
}
}
class BiJiao02 implements Comparator{
@Override
public int compare(Student o1, Student o2) {
// 比较名字
return o1.getName().compareTo(o2.getName());
}
}
class BiJiao03 implements Comparator{
@Override
public int compare(Student o1, Student o2) {
if(o1.getAge() == o2.getAge()){
return o1.getName().compareTo(o2.getName());
}else{
return o1.getAge() - o2.getAge();
}
}
}
public class Test01 {
public static void main(String[] args) {
Student s1 = new Student(20,160.5,"nannan");
Student s2 = new Student(21,170.5,"shuaishuai");
// 比较身高
Comparator comparator = new BiJiao01();
comparator.compare(s1,s2);
// 比较姓名 多态的应用
Comparator comparator1 = new BiJiao02();
comparator1.compare(s1,s2);
}
}
【4】外部比较器与内部比较器的比较
外部比较器比内部比较器好,运用到多态,扩展性好
【1】存入Integer类型的数据 (底层使用内部比较器)
public class Test01 {
public static void main(String[] args) {
TreeSet ts = new TreeSet<>();
ts.add(12);
ts.add(3);
ts.add(7);
ts.add(9);
ts.add(3);
ts.add(16);
int size = ts.size();
System.out.println(size);
System.out.println(ts);
}
}
特点:唯一,无序(没有按照输入顺序进行输出),有序(按照升序进行遍历)
【2】原理:底层:二叉树(数据结构中的一种逻辑结构)
【4】放入自定义Student类型的数据
public class Student implements Comparable{ private int age; private int height; private String name; public Student(int age, int height, String name) { this.age = age; this.height = height; this.name = name; } public Student() { } @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 && height == student.height && Objects.equals(name, student.name); } @Override public String toString() { return "Student{" + "age=" + age + ", height=" + height + ", name='" + name + ''' + '}'; } @Override public int hashCode() { return Objects.hash(age, height, name); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public int compareTo(Student o) { return this.getAge() - o.getAge(); } }
利用内部比较器
public class Test03 {
public static void main(String[] args) {
// 利用内部比较器
TreeSet treeSet = new TreeSet<>();
treeSet.add(new Student(10,190,"elili"));
treeSet.add(new Student(10,190,"flili"));
treeSet.add(new Student(8,160,"blili"));
treeSet.add(new Student(12,150,"alili"));
System.out.println(treeSet);
//[Student{age=8, height=160, name='blili'}, Student{age=10, height=190, name='elili'}, Student{age=12, height=150, name='alili'}]
}
}
利用外部比较器
public class Test04 {
public static void main(String[] args) {
Comparator comparator = new Comparator() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
};
TreeSet treeSet = new TreeSet<>(comparator);
treeSet.add(new Student(10,190,"elili"));
treeSet.add(new Student(10,190,"flili"));
treeSet.add(new Student(8,160,"blili"));
treeSet.add(new Student(12,150,"alili"));
System.out.println(treeSet);
}
}
public class Test04 {
public static void main(String[] args) {
TreeSet treeSet = new TreeSet<>(new Comparator() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
});
treeSet.add(new Student(10,190,"elili"));
treeSet.add(new Student(10,190,"flili"));
treeSet.add(new Student(8,160,"blili"));
treeSet.add(new Student(12,150,"alili"));
System.out.println(treeSet);
}
}
【4】TreeSet底层的二叉树的遍历时按照升序的结果出现的这个升序是靠中序遍历得到的
public class Test01 {
public static void main(String[] args) {
Map map = new HashMap();
map.put("lili",12);
map.put("Alice",13);
map.put("feifei",15);
map.put("lili",13);
int size = map.size();
System.out.println(size);
System.out.println(map);
//map.clear(); 清空
map.remove("lili"); // 移除
map.containsKey("lili"); // 是或否包含指定的key
map.containsValue(15); // 是否包含指定的Value
map.isEmpty(); // 判断集合是否为空
Integer alice = map.get("Alice"); // 返回指定key对应的value
System.out.println("-------------------------------");
Set strs = map.keySet(); // 获取集合中的全部key
for (String str : strs) {
System.out.println(str);
}
Collection values = map.values(); // 获取集合中的全部value值
for (Integer value : values) {
System.out.println(value);
}
System.out.println("-------------------------------");
Set set = map.keySet(); // 获取集合中全部的key值
for (String s : set) {
System.out.println(map.get(s));
}
Set> entries = map.entrySet();
for (Map.Entry entry : entries) {
entry.getKey();
entry.getValue();
}
}
}
TreeMap实现类
【1】key的类型为String类型
public class Test02 {
public static void main(String[] args) {
Map map = new TreeMap<>();
map.put("blili",1234);
map.put("alili",2345);
map.put("blili",5487);
map.put("clili",5698);
map.put("dlili",2343);
int size = map.size();
System.out.println(size);
System.out.println(map);// {alili=2345, blili=5487, clili=5698, dlili=2343}
}
}
【2】key的类型为自定义类型.
内部比较器
public class Student implements Comparable{ private int age; private String name; private int height; public Student(int age, String name, int height) { this.age = age; this.name = name; this.height = height; } @Override public int compareTo(Student o) { return this.getAge() - o.getAge(); } @Override public String toString() { return "Student{" + "age=" + age + ", name='" + name + ''' + ", height=" + height + '}'; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } }
public class Test03 {
public static void main(String[] args) {
Map map = new TreeMap<>();
map.put(new Student(19,"blili",170),1001);
map.put(new Student(18,"blili",150),1003);
map.put(new Student(19,"alili",180),1023);
map.put(new Student(17,"clili",170),1001);
map.put(new Student(10,"dlili",140),1546);
map.put(new Student(19,"blili",130),1254);
System.out.println(map);
System.out.println(map.size());
}
}
外部比较器
public class Test03 {
public static void main(String[] args) {
Comparator com = new Comparator() {
@Override
public int compare(Student o1, Student o2) {
return o1.getAge() - o2.getAge();
}
}
Map map = new TreeMap<>(com);
map.put(new Student(19,"blili",170),1001);
map.put(new Student(18,"blili",150),1003);
map.put(new Student(19,"alili",180),1023);
map.put(new Student(17,"clili",170),1001);
map.put(new Student(10,"dlili",140),1546);
map.put(new Student(19,"blili",130),1254);
System.out.println(map);
System.out.println(map.size());
}
}
HashMap 底层源码
TreeMap底层源码
public class TreeMapTreeSet底层源码{ // 重要属性 // 外部比较器 private final Comparator super K> comparator; // 树的根节点 private transient Entry root = null; // 集合中元素的数量 private transient int size = 0; // 空构造器: public TreeMap() { // 如果使用空构造器,底层就不使用外部构造器 comparator = null; } // 有参构造器 public TreeMap(Comparator super K> comparator) { // 如果使用有参构造器,相当于指定了外部构造器 this.comparator = comparator; } public V put(K key, V value) {// K V 在创建对象时,就以确认 // 如果放入的是第一对元素,那么t的值是null Entry t = root;// 在放入第二个节点的时候,root已经是根节点了 if (t == null) {// 如果放入第一对元素,会执行这里 compare(key, key); // type (and possibly null) check // 根节点确认为root节点 key value parent root = new Entry<>(key, value, null); size = 1; modCount++; return null; } int cmp; Entry parent; // split comparator and comparable paths // 将外部比较器赋给cpr Comparator super K> cpr = comparator; // cpr不为null 意味着使用了有参构造器,指定了外部比较器 if (cpr != null) { do { parent = t; // 将元素的key值做比较 cmp = cpr.compare(key, t.key); // cpr返回的就是一个int类型的值 if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else// cmp == 0 return t.setValue(value); } while (t != null); } else { // 没有使用外部比较器, 使用内部比较器 if (key == null) throw new NullPointerException(); Comparable super K> k = (Comparable super K>) key; do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } Entry e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; fixAfterInsertion(e); size++; modCount++; return null; } }
public class TreeSetCollections工具类extends AbstractSet { // 重要属性 private transient NavigableMap m; private static final Object PRESENT = new Object(); // 在调用空构造器的时候,底层创建了一个TreeMap public TreeSet() { this(new TreeMap ()); } // TreeMap implements NavigableMap TreeSet(NavigableMap m) { this.m = m; } public boolean add(E e) { return m.put(e, PRESENT)==null; } }
public class Test06 {
public static void main(String[] args) {
//Collections不支持创建对象,构造器私有化
ArrayList list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
Collections.addAll(list,"dd","ee");
Collections.addAll(list,new String[]{"gg","pp"});
// sort
Collections.sort(list);
// binarySearch
int ccIndex = Collections.binarySearch(list, "cc");
System.out.println(ccIndex);
// copy 将arr2上的内容替换到list上
ArrayList arr2 = new ArrayList<>();
Collections.addAll(arr2,"tt","ss");
Collections.copy(list,arr2);
// fill 填充
Collections.fill(arr2,"yy");
}
}



