数据结构 集合

1、数组和集合

数组:数组长度在初始化的时候就已经固定,不适合对象数量未知的情况。

集合(collection、map):长度可变,功能更多。

2、集合(集合有两个基本接口collection和map)

下图为collection(图片来源于http://blog.csdn.net/Liveor_Die的博客)

è¿éåå¾çæè¿°

下图为map(图片来源于网络)

数据结构 集合_第1张图片

1.介绍一下list比较常用的集合:(有序,值允许重复)

1)ArrayList:

底层实现:


    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    transient Object[] elementData; // non-private to simplify nested class access
    
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

初始化方法初始化了一个数组,底层实现为数组。既然是数组,了解下如何实现数组长度的自动化增长。

int newCapacity = oldCapacity + (oldCapacity >> 1);

最关键的一句代码,差不多就是一次增加原有长度的一半,当然还有其他特殊情况的处理,就不详细说了。

特点:末尾添加/删除数据时速度较快,向中间set/remove数据较慢,随机查询效率很高(因为有索引)。

2)LinkedList:

底层实现:

    private static class Node {
        E item;
        Node next;
        Node prev;

        Node(Node prev, E element, Node next) {
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }

从上图可以看出来是链表,因为有next和prev所以是双向链表。

下面是remove方法的实现代码

    public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }

用遍历来实现,效率肯定低,数据越多效率越低。

特点:add/set/remove方法较快(只需要改变指针地址),随机访问较慢(需要遍历整个链表)。

3)Vector

底层实现:和ArrayList一样是数组,不过Vector所有方法上都有synchronized保证其线程安全。

特点:线程安全,效率低。

2.简单介绍下set:(HashSet无序,不允许有重复值)

HashSet:基于HashMap实现,只存储值,没有key(map中key的位置放置值,value位置放置一个new Object())

HashSet与HashMap的区别:HashMap中keys的元素有校验重复,所以HashSet中存储的对象都会先校验下hashcode。

LinkedHashSet:基于LinkedHashMap实现,保证了元素的有序。

TreeSet:基于TreeMap实现,保证有序。

3.简单介绍下queue:

Deque:双向队列,deque是个接口,实现类有ArrayDeque(底层实现为数组),LinkedDeque(底层实现为链表)。总体来说,arrayDeque要比LinkedDeque性能高。

PriorityQueue:优先级队列,底层实现也是数组,优先级排序,需要实现Comparator(排序方法暂未了解)。

4.另一个基本接口Map

1)HashMap:底层实现为哈希表,所以存储数组不能保证有序。源码如下:

transient Node[] table;

在调用put方法时,会判断table是否为null,如果为null则进行初始化。下边是默认初始化大小:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

当每次数组存满时,当前数组容量小于最大数量(2^30)并且大于初始化容量时,数组容量*2,增加的量如下:

        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        }

HashMap的keys不允许有重复,可以为null,利用hashcode校验keys是否重复,代码如下;

    static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

2)Hashtable

hashtable在hashmap的基础上所有方法都加上了synchronized关键字。并且在读写操作中限制了key不能为null,否则抛出空指针异常。

3)LinkedHashMap

基于双向链表实现,实际上就是在HashMap中的Node对象中增加了before和after对象,分别存储了上一次put和下一次put的值,以此来维护数据的存入顺序。

    static class Entry extends HashMap.Node {
        Entry before, after;
        Entry(int hash, K key, V value, Node next) {
            super(hash, key, value, next);
        }
    }

4)TreeMap

基于红黑树实现的,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序。不能够记录存入顺序。

3.红黑树

红黑树属于平衡二叉树的一种,数据在存入的时候,会根据数据大小进行排序,即左子节点<根节点<右子节点,所以在查找元素的时候,可以直接和根节点进行比较,如果小于根节点,则向左查找,如果大于根节点,则向右查找,所以查找效率比较高。下边是红黑树的一个图:

(图片来源于:https://blog.csdn.net/q3244676719/article/details/81540830)

关于红黑树的右旋和左旋,请移步至:https://blog.csdn.net/q3244676719/article/details/81540830

(本文部分内容参考上链接总结而出)

 

你可能感兴趣的:(数据结构 集合)