数据结构与算法

1、数据结构

  • 数据结构:就是在计算机的缓存、内存、硬盘中如何组织管理数据的。重点在结构。
  • 数据结构分为
    • 逻辑结构:思想上的结构,线性表(数组、链表),图,树,栈,队列
    • 物理结构:真实结构,紧密结构(顺序结构),跳转结构(链式结构)
      • 紧密结构:以数组为例,优点:寻址快—>查找元素块;缺点:删除和增加元素效率低
        在这里插入图片描述

      • 跳转结构:以链表(单向、双向、循环链表)为例,优点:删除和插入元素效率高,查询元素效率低

2、集合

  • 数组、集合都是对多个数据进行存储操作的,简称容器
    • 这些数据的存储是内存层面的存储,而不是持久化存储(.txt、.avi、.jpg、数据库)。
    • 数组:长度一旦确定,不可修改。一旦声明了类型,那就只能存放这一种类型的数据。删除、增加元素效率低;数组中实际元素的数量是没有办法获取的;存储有序,可重复。为了解决数组以上缺点,于是引入了集合
      在这里插入图片描述

2.1 Collection

  • 迭代器简要原理图
    在这里插入图片描述
import java.util.*;

public class Test {
    public static void main(String[] args) {
        /**
         * Collection接口的常用方法:
         *         增加:add(E e) addAll(Collection<? extends E> c)
         *         删除:clear() remove(Object o)
         *         修改:
         *         查看:iterator() size()
         *         判断:contains(Object 0) equals(Object o) isEmpty()
         */

        //创建对象;接口不能创建对象,利用实现类创建对象
        Collection col = new ArrayList();

        //调用方法
        //集合只能存储引用类型的数据,不能是基本类型数据,基本类型自动装箱,对应包装类型
        col.add(18);
        col.add(12);
        col.add(11);
        col.add(17);

        System.out.println(col/*.toString()*/);//[18, 12, 11, 17]

        List list = Arrays.asList(new Integer[]{11, 15, 3, 7, 1});

        col.addAll(list);

        System.out.println(col);//[18, 12, 11, 17, 11, 15, 3, 7, 1]

//        col.clear();
//        System.out.println(col);//[]
//        System.out.println("集合中的元素的数量为:" + col.size());//集合中的元素的数量为:0
//        System.out.println("集合是否为空:" + col.isEmpty());//集合是否为空:true

        boolean isRemove = col.remove(15);
        System.out.println(col); //[18, 12, 11, 17, 11, 3, 7, 1]
        System.out.println("集合中数据是否删除:" + isRemove); //true

        Collection col2 = new ArrayList();
        col2.add(18);
        col2.add(12);
        col2.add(11);
        col2.add(17);

        Collection col3 = new ArrayList();
        col3.add(18);
        col3.add(12);
        col3.add(11);
        col3.add(17);

        System.out.println(col2.equals(col3)); //true
        System.out.println(col2 == col3); //false 比较的是地址,地址一定不相等

        System.out.println("是否包含元素:" + col3.contains(17));//true

        //对集合遍历
        //方式1:普通for循环
//       Collection不能用普通for循环
        //方式2:增强for循环
        for(Object o : col){
            System.out.println(o);
        }

        //方式3:iterator()
        Iterator it = col.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }

        System.out.println("===============");

        for(Iterator ite = col.iterator();ite.hasNext();){
            System.out.println(ite.next());
        }
    }
}

2.1.1 List

import java.util.*;

public class Test {
    public static void main(String[] args) {
        /**
         * List 接口的常用方法:
         *         增加:add(int index,E element)
         *         删除:remove(int index) remove(Object o)
         *         修改:set(int index,E element)
         *         查看:get(int index)
         *         判断:
         */

        //创建对象;接口不能创建对象,利用实现类创建对象
        List list = new ArrayList();


        list.add(18);
        list.add(12);
        list.add(11);
        list.add(17);
        list.add(2);
        list.add("abc");

        System.out.println(list); //[18, 12, 11, 17, 2, abc]

        list.add(3,66);

        System.out.println(list); //[18, 12, 11, 66, 17, 2, abc]

        list.set(3,77);
        System.out.println(list); //[18, 12, 11, 77, 17, 2, abc]

        list.remove(2);
        System.out.println(list); //[18, 12, 77, 17, 2, abc]

        list.remove("abc");
        System.out.println(list); //[18, 12, 77, 17, 2]

        Object o = list.get(0); //18
        System.out.println(o);

        System.out.println("====================");
        //List集合 遍历
        //方式1:普通for循环
        for(int i = 0;i < list.size();i++){
            System.out.println(list.get(i));
        }
        System.out.println("====================");
        //方式2:增强for循环
        for (Object obj : list) {
            System.out.println(obj);
        }
        System.out.println("====================");
        //方式3:迭代器
        Iterator it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("====================");
        for(Iterator ite = list.iterator();ite.hasNext();){
            System.out.println(ite.next());
        }
    }
}
2.1.1.1 ArrayList
  • JDK1.7源码
    • ArrayList实现List接口的失误,由于AbstractList父类实现了List接口,所以子类ArrayList不需要重新实现List接口,后期的版本也没有修正
    • 底层是数组,在调用构造器的时候,数组长度初始化10,扩容的时候扩展为原数组的1.5倍
    • 底层重要属性
      在这里插入图片描述
    • JDK1.7中,ArrayList对应的内存, ArrayList a1 = new ArrayList();调用空构造器
      在这里插入图片描述
    • 调用add()在这里插入图片描述
    • 当数组中的10个位置都满了的时候就开始进行数组的扩容,扩容长度为元素组的1.5倍
      在这里插入图片描述
      在这里插入图片描述
  • JDK1.8源码
    • 底层依旧是Object类型的数组,size是数组中有效长度
      在这里插入图片描述
    • ArrayList a1 = new ArrayList();在调用空构造器的时候,底层elementData数组的初始化为{}
      在这里插入图片描述
    • 调用add()
      在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
    • 底层仍然是一个数组,在调用构造器的时候,底层数组为{},在调用add方法以后底层数组才重新赋值为新数组,新数组的长度为10,这样做节省了内存,在add后才创建长度为10的数组
2.1.1.2 Vector
  • 底层Object数组,int类型属性标书数组中有效长度
    在这里插入图片描述
  • Vector v = new Vector();调用构造器
    在这里插入图片描述
  • 调用add()
    在这里插入图片描述
  • ArrayList实现类和Vector实现类的区别与联系
    • 联系:底层都是数组的扩容,数组的优点:查询效率高;数组的缺点:删除、增加元素效率低,数组的特点:数据是可重复的
    • 区别:ArrayList底层扩容长度为原数组的1.5倍,线程不安全,效率高;而Vector底层扩容长度为原数组的2倍,线程安全,效率低
2.1.1.3 LinkedList
import java.util.Iterator;
import java.util.LinkedList;

public class Test {
    public static void main(String[] args) {
        /**
         * LinkedList接口的常用方法:
         *         增加:addFirst(E e) addLast(E e) offer(E e) offerFirst(E e) offerLast(E e)
         *         删除:poll() poolFirst() poolLast() JDK1.6以后新出的方法,提高代码的健壮性
         *              removeFirst() removeLast()
         *         修改:
         *         查看:element() getFirst() getLast() indexOf(Object o) lastIndexOf(Object o)
         *              peek() peekFirst() peekLast()
         *         判断:
         */
        //创建LinkedList集合对象
        LinkedList<String> list = new LinkedList<>();
        list.add("aaaa");
        list.add("bbbb");
        list.add("cccc");
        list.add("dddd");
        list.add("bbbb");
        list.add("eeee");
        list.add("ffff");

        System.out.println(list);//[aaaa, bbbb, cccc, dddd, bbbb, eeee, ffff];LinkedList可以添加重复的数据

        list.addFirst("jj");
        list.addLast("hh");
        System.out.println(list);//[jj, aaaa, bbbb, cccc, dddd, bbbb, eeee, ffff, hh]

        list.offer("kk");//添加元素在末尾
        System.out.println(list);//[jj, aaaa, bbbb, cccc, dddd, bbbb, eeee, ffff, hh, kk]
        list.offerFirst("pp");
        list.offerLast("rr");
        System.out.println(list);//[pp, jj, aaaa, bbbb, cccc, dddd, bbbb, eeee, ffff, hh, kk, rr]
        System.out.println(list.poll()/*删除头元素*/);//pp
        System.out.println(list);//[jj, aaaa, bbbb, cccc, dddd, bbbb, eeee, ffff, hh, kk, rr]
        System.out.println(list.pollFirst());//jj
        System.out.println(list.pollLast());//rr
        System.out.println(list.removeFirst());//aaaa
        System.out.println(list.removeLast());//kk

//        list.clear();
//        System.out.println(list);//[]
//        System.out.println(list.pollFirst());//null
//        System.out.println(list.removeFirst()); //会报错,Exception in thread "main" java.util.NoSuchElementException,不友好
        //普通for循环
        for(int i = 0;i < list.size();i++){
            System.out.println(list.get(i));
        }
        //增强for循环
        for (String s : list) {
            System.out.println(s);
        }
        //while循环的迭代器
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }

        //for循环的迭代器,此方式节省内存
        for(Iterator<String> ite = list.iterator();it.hasNext();){
            System.out.println(ite.next());
        }
    }
}
  • LinkedList数据结构
    • 物理结构:跳转结构
    • 逻辑结构:线性表(链表)
    • 双向链表
      在这里插入图片描述
2.1.1.3.1 自定义LinkedList
public class Node {//结点类
    //三个属性
    //上一个元素的地址
    private Node pre;
    //当前存入的元素
    private Object obj;
    //下一个元素地址
    private Node 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;
    }

    @Override
    public String toString() {
        return "Node{" +
                "pre=" + pre +
                ", obj=" + obj +
                ", next=" + next +
                '}';
    }
}


public class MyLinkedList {
    //链中一定有一个首节点
    Node first;
    //链中一定有一个尾结点
    Node last;
    //计数器
    int count = 0;
    //提供一个构造器
    public MyLinkedList(){}

    //添加元素方法
    public void add(Object o){
        if(first == null){//证明添加的元素是第一个结点
            Node n = new Node();
            n.setPre(null);
            n.setObj(o);
            n.setNext(null);
            //当前链中第一个节点变为n
            first = n;
            //当前链中最后一个节点变为n
            last = n;
        }else{
            Node n = new Node();
            n.setPre(last); //n的上一个结点
            n.setObj(o);
            n.setNext(null);
            last.setNext(n);
            last = n;
        }
        //链中元素数量加1
        count++;
    }

    //得到集合中元素的数量
    public int getSize(){
        return count;
    }

    //通过下标得到元素
    public Object get(int index){
        //获取链表的头元素
        Node n = first;
        for(int i = 0;i < index;i++){
            n = n.getNext();
        }
        return n.getObj();
    }
}

class Test{
    public static void main(String[] args) {
        //创建一个集合对象
        MyLinkedList ml = new MyLinkedList();
        ml.add("aa");
        ml.add("bb");
        ml.add("cc");

        System.out.println(ml.getSize());
        System.out.println(ml.get(2));
    }
}
2.1.1.3.2 LinkedList源码
  • JDK1.8 底层链表是双向链表
    在这里插入图片描述
    在这里插入图片描述
2.1.1.4 迭代器
  • iterator()、Iterator、Iterable关系
    在这里插入图片描述
  • hasNext(),next()的具体实现,增强for循环也是通过迭代器实现的
    在这里插入图片描述
2.1.1.5 ListIterator迭代器

在这里插入图片描述

  • 报并发修改异常:就是Iterator迭代器和list同时对集合进行操作造成的
import java.util.ArrayList;
import java.util.Iterator;

public class Test2 {
    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");

        //在"cc"之后添加一个字符串"kk"
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            if("cc".equals(it.next())){
                list.add("kk"); //报并发修改异常;Exception in thread "main" java.util.ConcurrentModificationException
            }
        }
    }
}

在这里插入图片描述

  • 解决并发修改异常的办法:事情让一个"人"来做—>所以就引入了新的迭代器:ListIterator
import java.util.ArrayList;
import java.util.ListIterator;

public class Test2 {
    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");

        //在"cc"之后添加一个字符串"kk"
        ListIterator<String> it = list.listIterator();
        while(it.hasNext()){
            if("cc".equals(it.next())){
                it.add("kk");
            }
        }

        System.out.println(it.hasNext()); //false
        System.out.println(it.hasPrevious()); //true
        //逆向遍历
        while(it.hasPrevious()){
            System.out.println(it.previous());
        }
        System.out.println(it.hasNext()); //true
        System.out.println(it.hasPrevious()); //false
        System.out.println(list); //[aa, bb, cc, kk, dd, ee]
    }
}

2.1.2 Set

  • 唯一、无序
  • 底层原理:数组+链表 = 哈希表
  • 没有跟索引相关的方法
  • 遍历方法:1、迭代器;2、增强for循环
2.1.2.1 HashSet底层原理图
  • HashSet底层是HashMap来实现
    在这里插入图片描述

在这里插入图片描述

  • int类型数据比较:将比较的数据做差,然后返回一个int类型的数据,将这个int类型的数值 按照=0 >0 <0
    在这里插入图片描述

  • String类型数据比较
    在这里插入图片描述

  • 比较double类型数据
    在这里插入图片描述

  • 比较自定义类型数据
    (1)、内部比较器

public class Student implements Comparable<Student>{
    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;
    }

    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 String toString() {
        return "Student{" +
                "age=" + age +
                ", height=" + height +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        //按照年龄进行比较
//      return this.age - o.getAge();
        //按照身高比较
//        return ((Double)this.height).compareTo((Double)o.getHeight());
        //按照名字比较
        return this.name.compareTo(o.getName());
    }
}
public class Test01 {
    public static void main(String[] args) {
        //比较两个学生
        Student s1 = new Student(10,160.5,"lili");
        Student s2 = new Student(14,170.5,"nana");
        System.out.println(s1.compareTo(s2));
    }
}

(2)、外部比较器,内部比较器和外部比较器,推荐使用外部比较器,多态,扩展性好

import java.util.Comparator;

public class Student{
    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;
    }

    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 String toString() {
        return "Student{" +
                "age=" + age +
                ", height=" + height +
                ", name='" + name + '\'' +
                '}';
    }
}

class ComparatorImp1 implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        //比较年龄
        return o1.getAge() - o2.getAge();
    }
}

class ComparatorImp2 implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        //比较年龄
        return o1.getName().compareTo(o2.getName());
    }
}

class ComparatorImp3 implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        //年龄相同的情况下,比较身高
        if((o1.getAge() ^ o2.getAge()) == 0){
            return ((Double)o1.getHeight()).compareTo((Double) o2.getHeight());
        }
        return o1.getAge() - o2.getAge();
    }
}
public class Test01 {
    public static void main(String[] args) {
        //比较两个学生
        Student s1 = new Student(10,160.5,"lili");
        Student s2 = new Student(14,170.5,"nana");

        //比较年龄
        Comparator com = new ComparatorImp1();
        System.out.println(com.compare(s1, s2));

        //比较姓名
        Comparator com2 = new ComparatorImp2();
        System.out.println(com2.compare(s1,s2));

		//年龄相同,比较身高
        Comparator com3 = new ComparatorImp2();
        System.out.println(com2.compare(s1,s2));
    }
}
2.1.2.2 LinkedHashSet
  • 唯一,有序(按照输入顺序进行输出)
  • 在HashSet的基础上,多了一个总的链表,这个总链表将放入的元素串在一起,方便有序的遍历
2.1.2.3 TreeSet

在这里插入图片描述

  • 唯一,升序
  • 底层是二叉树,在树中放入数据的时候,最重要的是比较,通过内部比较器或者外部比较器实现的比较
  • Integer类型的数据,底层利用的是内部比较器
  • String类型的数据,底层利用的是内部比较器
  • 自定义类型的数据,对于自定义的数据必须实现比较器,底层可以用内部比较器和外部比较器
  • TreeSet在进行遍历的时候得到的是升序的结果,是靠中序遍历实现
  • 二叉树的遍历:
    • 中序遍历:左 根 右
    • 先序遍历:根 左 右
    • 后序遍历:左 右 根
      (1)、内部比较器
public class Student implements Comparable<Student>{
    private int age;
    private String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.getAge();
    }
}


import java.util.TreeSet;

public class Test01 {
    public static void main(String[] args) {
        //创建一个TreeSet
        TreeSet<Student> ts = new TreeSet<>();
        ts.add(new Student(10,"lili"));
        ts.add(new Student(10,"lili"));
        ts.add(new Student(8,"alili"));
        ts.add(new Student(10,"clili"));

        System.out.println(ts.size());
        System.out.println(ts);
    }
}

(2)、外部比较器

import java.util.Comparator;

public class Student{
    private int age;
    private String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

class ComparatorImp implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.getAge() - o2.getAge();
    }
}


import java.util.Comparator;
import java.util.TreeSet;

public class Test01 {
    public static void main(String[] args) {
        //创建一个TreeSet
        Comparator<Student> com = new ComparatorImp();
        TreeSet<Student> ts = new TreeSet<>(com);//一旦制定外部比较器,那么就会按照外部比较器来比较
        ts.add(new Student(10,"lili"));
        ts.add(new Student(10,"lili"));
        ts.add(new Student(8,"alili"));
        ts.add(new Student(10,"clili"));

        System.out.println(ts.size());
        System.out.println(ts);
    }
}

(3)、利用匿名内部类的外部比较器

public class Student{
    private int age;
    private String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    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;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}


import java.util.TreeSet;

public class Test01 {
    public static void main(String[] args) {
        //创建一个TreeSet
        //利用匿名内部类实现的外部比较器,那么就会按照外部比较器来比较
        TreeSet<Student> ts = new TreeSet<>((o1,o2) -> o1.getAge() - o2.getAge());
        ts.add(new Student(10,"lili"));
        ts.add(new Student(10,"lili"));
        ts.add(new Student(8,"alili"));
        ts.add(new Student(10,"clili"));

        System.out.println(ts.size());
        System.out.println(ts);
    }
}

2.2 Map

在这里插入图片描述

  • 唯一,无序
  • HashMap
    在这里插入图片描述

2.2.1 HashMap源码

  • 加载因子为什么是0.75?
    • 加载因子设置为1:空间利用率得到了很大的满足,很容易碰撞,产生链表---->查询效率低
    • 加载因子设置为0.5:碰撞的概率低,扩容,产生的链表的几率低,查询效率高,空间利用率太低。
  • 主数组的长度为什么必须为 2^n:
    • h & (length - 1)等效与h%length操作,等效的前提是:length必须是2的整数倍
    • 防止哈希冲突,位置冲突
      在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • h&(length - 1)与h%length等效的
    在这里插入图片描述

2.2.2 TreeMap源码

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.3 Collections

  • 工具类,不能创建对象,只能用类名调用
import java.util.ArrayList;
import java.util.Collections;

public class Test {
    public static void main(String[] args) {
        //Collections不能创建对象,因为构造器私有化了
        //里面的属性和方法都是被static修饰,可以直接用类名去调用
        ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("cc");
        list.add("bb");
        list.add("dd");

        //addAll
        Collections.addAll(list,"fee","fff","ggg");
        System.out.println(list);//[aa, cc, bb, dd, fee, fff, ggg]

        Collections.addAll(list,new String[]{"pp","oo","gg"});
        System.out.println(list);//[aa, cc, bb, dd, fee, fff, ggg, pp, oo, gg]

        //binarySearch必须在有序的集合中查找:所以集合先要排序
        Collections.sort(list);
        System.out.println(list);//[aa, bb, cc, dd, fee, fff, gg, ggg, oo, pp]

        //binarySearch
        System.out.println(Collections.binarySearch(list, "cc"));//2

        //copy
        ArrayList<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"tt","ss");
        Collections.copy(list,list2);//将list2的内容替换到list上去;
        System.out.println(list);//[tt, ss, cc, dd, fee, fff, gg, ggg, oo, pp]
        System.out.println(list2);//[tt, ss]

        //fill
        Collections.fill(list2,"yyy");
        System.out.println(list2);//[yyy, yyy]
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值