JAVA编程基础:数据结构与算法

1. 数据结构

  • 数据结构的研究对象:

    • ① 数据间的逻辑关系(集合关系、一对一、一对多、多对多)

    • ② 数据的存储结构(或物理结构)

      • 角度一:顺序结构、链式结构、索引结构、哈希结构

      • 角度二:线性表:一对一关系(一维数组、链表、栈、队列)、树(二叉树、B+树)、图(多对多)、哈希表(HashMap、HashSet)

    • ③ 相关运算

      • 分配资源,建立结构,释放资源;插入和删除;获取和遍历;修改和排序

  • 树(了解)

  • 相关数据结构的核心Node的设计(单向链表、双向链表、二叉树、栈、队列)(理解)

  • 常见存储结构之:链表
    链表中的基本单位是:节点(Node)
    单向链表
    class Node{
        Object data;
        Node next;
        public Node(Object data){
            this.data = data;
        }
    
    }
    创建对象:
    Node node1 = new Node("AA");
    Node node2 = new Node("BB");
    node1.next = node2;
    双向链表
    class Node{
        Node prev;
        Object data;
        Node next;
        public Node(Object data){
            this.data = data;
        }
        public Node(Node prev,Object data,Node next){
            this.prev = prev;
            this.data = data;
            this.next = next;
        }
    }
    创建对象:
    Node node1 = new Node(null,"AA",null);
    Node node2 = new Node(node1,"BB",null);
    Node node3 = new Node(node2,"CC",null);
    node1.next = node2;
    node2.next = node3;
    
    
    常见存储结构之:二叉树
    
    class TreeNode{
        TreeNode left;
        Object data;
        TreeNode right;
        public TreeNode(Object data){
            this.data = data;
        }
        public TreeNode(TreeNode left,Object data,TreeNode right){
            this.left = left;
            this.data = data;
            this.right = right;
        }
    }
    创建对象:
    TreeNode node1 = new TreeNode(null,"AA",null);
    TreeNode leftNode = new TreeNode(null,"BB",null);
    TreeNode rightNode = new TreeNode(null,"CC",null);
    node1.left = leftNode;
    node1.right = rightNode;
    或
    class TreeNode{
        TreeNode parent;
        TreeNode left;
        Object data;
        TreeNode right;
        public TreeNode(Object data){
            this.data = data;
        }
        public TreeNode(TreeNode left,Object data,TreeNode right){
            this.left = left;
            this.data = data;
            this.right = right;
        }
        public TreeNode(TreeNode parent,TreeNode left,Object data,TreeNode right){
            this.parent = parent;
            this.left = left;
            this.data = data;
            this.right = right;
        }
    }
    创建对象:
    TreeNode node1 = new TreeNode(null,null,"AA",null);
    TreeNode leftNode = new TreeNode(node1,null,"BB",null);
    TreeNode rightNode = new TreeNode(node1,null,"CC",null);
    node1.left = leftNode;
    node1.right = rightNode;
    
    常见存储结构之:栈(stack、先进后出、first in last out、FILO、LIFO)
    > 属于抽象数据类型(ADT)
    > 可以使用数组或链表来构建
    数组实现栈
    class Stack{
        Object[] values;
        int size;//记录存储的元素的个数
        public Stack(int length){
            values = new Object[length];
        }
        //入栈
        public void push(Object ele){
            if(size >= values.length){
                throw new RuntimeException("栈空间已满,入栈失败");
            }
            values[size] = ele;
            size++;
        }
        //出栈
        public Object pop(){
            if(size <= 0){
                throw new RuntimeException("栈空间已空,出栈失败");
            }
            Object obj = values[size - 1];
            values[size - 1] = null;
            size--;
            return obj;
        }
    }
    常见存储结构之:队列(queue、先进先出、first in first out、FIFO)
    > 属于抽象数据类型(ADT)
    > 可以使用数组或链表来构建
    数组实现队列
    class Queue{
        Object[] values;
        int size;//记录存储的元素的个数
        public Queue(int length){
            values = new Object[length];
        }
        public void add(Object ele){ //添加
            if(size >= values.length){
                throw new RuntimeException("队列已满,添加失败");
            }
            values[size] = ele;
            size++;
        }
        public Object get(){  //获取
            if(size <= 0){
                throw new RuntimeException("队列已空,获取失败");
            }
            Object obj = values[0];
            //数据前移
            for(int i = 0;i < size - 1;i++){
                values[i] = values[i + 1];
            }
            //最后一个元素置空
            vlaues[size - 1] = null;
            size--;
            return obj;
        }
    }
    
    

2. List接口下的实现类的源码剖析

  • 层次1:

  • |-----子接口:List:存储有序的、可重复的数据 ("动态"数组)
           |---- ArrayList:List的主要实现类;线程不安全的、效率高;底层使用Object[]数组存储
                           在添加数据、查找数据时,效率较高;在插入、删除数据时,效率较低
           |---- LinkedList:底层使用双向链表的方式进行存储;在对集合中的数据进行频繁的删除、插入操作时,建议使用此                         类在插入、删除数据时,效率较高;在添加数据、查找数据时,效率较低;
           |---- Vector:List的古老实现类;线程安全的、效率低;底层使用Object[]数组存储

  • 层次2:

  • //如下代码的执行:底层会初始化数组,即:Object[] elementData = new Object[]{};
    ArrayList<String> list = new ArrayList<>();
    
    list.add("AA"); //首次添加元素时,会初始化数组elementData = new Object[10];elementData[0] = "AA";
    list.add("BB");//elementData[1] = "BB";
    ...
    当要添加第11个元素的时候,底层的elementData数组已满,则需要扩容。默认扩容为原来长度的1.5倍。并将原有数组
    中的元素复制到新的数组中。

3.Map接口下的实现类的源码剖析

  • (掌握)HashMap的底层源码的剖析

  • HashMap中元素的特点
    > HashMap中的所有的key彼此之间是不可重复的、无序的。所有的key就构成一个Set集合。--->key所在的类要重写hashCode()和equals()
    > HashMap中的所有的value彼此之间是可重复的、无序的。所有的value就构成一个Collection集合。--->value所在的类要重写equals()
    > HashMap中的一个key-value,就构成了一个entry。
    > HashMap中的所有的entry彼此之间是不可重复的、无序的。所有的entry就构成了一个Set集合。

  • 在jdk8中,当我们创建了HashMap实例以后,底层并没有初始化table数组。当首次添加(key,value)时,进行判断,如果发现table尚未初始化,则对数组进行初始化。
    在jdk8中,HashMap底层定义了Node内部类,替换jdk7中的Entry内部类。意味着,我们创建的数组是Node[]
    在jdk8中,如果当前的(key,value)经过一系列判断之后,可以添加到当前的数组角标i中。如果此时角标i位置上有元素。在jdk7中是将新的(key,value)指向已有的旧的元素(头插法),而在jdk8中是旧的元素指向新的(key,value)元素(尾插法)。 "七上八下"
    jdk7:数组+单向链表
    jk8:数组+单向链表 + 红黑树
       什么时候会使用单向链表变为红黑树:如果数组索引i位置上的元素的个数达到8,并且数组的长度达到64时,我们就将此索引i位置上的多个元素改为使用红黑树的结构进行存储。
       什么时候会使用红黑树变为单向链表:当使用红黑树的索引i位置上的元素的个数低于6的时候,就会将红黑树结构退化为单向链表。
    属性/字段:

  • (熟悉)LinkedHashMap的底层源码的剖析

    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 默认的初始容量 16
    static final int MAXIMUM_CAPACITY = 1 << 30; //最大容量  1 << 30
    static final float DEFAULT_LOAD_FACTOR = 0.75f;  //默认加载因子
    static final int TREEIFY_THRESHOLD = 8; //默认树化阈值8,当链表的长度达到这个值后,要考虑树化
    static final int UNTREEIFY_THRESHOLD = 6;//默认反树化阈值6,当树中结点的个数达到此阈值后,要考虑变为链表
    
    //当单个的链表的结点个数达到8,并且table的长度达到64,才会树化。
    //当单个的链表的结点个数达到8,但是table的长度未达到64,会先扩容
    static final int MIN_TREEIFY_CAPACITY = 64; //最小树化容量64
    transient Node<K,V>[] table; //数组
    transient int size;  //记录有效映射关系的对数,也是Entry对象的个数
    int threshold; //阈值,当size达到阈值时,考虑扩容
    final float loadFactor; //加载因子,影响扩容的频率

  • LinkedHashMap在HashMap使用的数组+单向链表+红黑树的基础上,又增加了一对双向链表,记录添加的(key,value)的
    先后顺序。便于我们遍历所有的key-value。
    LinkedHashMap重写了HashMap的如下方法:

    Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
        LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e);
        linkNodeLast(p);
        return p;
    }
    底层结构:LinkedHashMap内部定义了一个Entry
    static class Entry<K,V> extends HashMap.Node<K,V> {
        Entry<K,V> before, after; //增加的一对双向链表
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
    }

  • (了解)HashSet、LinkedHashSet的底层源码的剖析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值