从数组、链表到集合

来源:互联网 发布:php7性能会赶上java吗 编辑:程序博客网 时间:2024/06/05 14:59

一、数组

概念

使用连续的一块内存空间保存,长度在初始化时确定。

时间复杂度

访问第n个元素时,时间复杂度为O(1);当访问某个特定的元素时,时间复杂度为O(n);
怎么理解这两个时间复杂度不一致的情况,举个例子

String[]strings=newString[]{"1","2","3"};    System.out.println(strings[0]);    for(Stringstr:strings){    if("1".equals(str)){    System.out.println("oyeah,findit!");    }    }

查找:如上代码中,找到数组中的第一个元素,时间复杂度就是O(1);如果找到1这个字符串元素,则时间复杂度是O(n);
修改:如上代码,删除末尾一个元素,时间复杂度为O(1);如果删除的是第一个元素那么时间复杂度是O(n);

二、链表

1.单链表

概念

在非连续的单元保存数据,并且通过指针将各个内存单元链接在一起;存在一个头结点指向第一个节点,最后一个节点域指向null。
时间复杂度:访问第n个元素,时间复杂度为O(n);当修改第n个元素,时间复杂度为O(1);
怎么理解这个时间复杂度:

这里写图片描述

查找:如图,链表的结构为不连续的单元,每个元素单元之间通过指针进行连接。当需要访问第三个元素时,就需要首先从链表的头部开始查找,然后通过链表的指针找到第二个元素data1,同理找到第三个元素data2.当需要访问第n个元素时,这时候时间复杂度为O(n);

修改:如果删除第2个元素

第一步:断开第一个节点、第二个的后继节点
第二步:修改第一个节点的后继节点为第三个节点,

全部操作,时间复杂度为O(1);

2.循环链表

概念

从结构上来说,循环链表对于单链表来说;仅仅是在尾节点的指针域上多了一个指向头结点的指针域,而单链表是将尾节点的指针域置为null。

3.双链表

概念

在单链表的基础上,每个节点都存在一个前继节点与后继节点。
从而双向链表对于单链表来说,双链表的结构相比更为复杂;每个节点都存在一个前继节点的指针域和一个后继节点的指针域。

对比

1.查找
单链表仅仅存在一个后继节点的指针域,这就导致了用单向链表来茶盏数据时,只能向后查找;而双向链表则可以进行前后的遍历查找。

2.修改

单链表对于增加和修改来说,都只需要修改一个数据的后继节点的指针域;而双向链表有结构的原因,在修改某个节点的时候,在修改数据、后继节点的指针域的同时还需要修改一个前继节点的指针域。相比来说,双向链表的效率相比要差。
正因为在空间和结构上的复杂带来的查找的提升,往往在维护的时候需要更多成本。

3.对比一下数组和链表的区别

数组是在初始时由一段已经固定好的连续的内存的空间组成的结构;而链表则是动态的由一系列不连续的内存区域构成的结构。

4.数组和链表在java中的应用

常见集合类底层结构

这里写图片描述

HashMap\HashTable\ConcurrentHashMap\TreeMap

HashMap与HashTable都是由数组和链表为底层数据结构的一种集合类,从结构上来说算是一种链表的数组。由于数组与链表本身的数据结构,数组在删除和增加操作时效率相比链表底下,链表在查找时效率又比不得数组,至于原因在上面介绍数组和链表的数据结构时已经说明,这里不再赘述。而HashMap则是结合了数组的寻址快速,链表的删除和增加快速的特点。详解HashMap 请移步http://blog.csdn.net/vking_wang/article/details/14166593。
而对比HashMap和HashTable的源码,可以发现最大的不同就是HashTable在可能出现线程安全的操作或变量上都加上了synchronized修饰。这样在多线程操作的情况下,每个线程都需要来竞争操作对象的锁。保证了在同一时刻,共享对象资源的仅仅只有一个线程在操作。也正是因为如此,所以在单线程的情况下,HashTable比HashMap效率要差的多。

而在jdk1.5之后,新增了concurrent包之后,新增了一个map集合类 ConcurrentHashMap 。ConcurrentHashMap 在能保证多线程操作不出现线程安全的情况下,又能保证一定的效率。为什么说是一定的效率呢?因为在本质上ConcurrentHashMap也是使用锁来实现的,而有所不同的是ConcurrentHashMap在HashMap的基础上新增了一个Segment的概念。与HashMap类似ConcurrentHashMap也是通过取得key的hash值来将对应的value存放在不同的已经加了锁的Segment之中。 将锁的粒度控制在Segment级别。


TreeMap 底层的数据结构为红黑树,不在本次数组、链表的讨论之列。
TreeMap默认排序为ASCII排序,相比于HashMap的无固定顺序,还是TreeMap有它的特殊的地方。例如:在默写支付的调用接口中,还是需要使用到这个TreeMap。

TreeMap 默认是根据Key来进行排序,如果想通过value排序,需要通过Comparator接口来实现。

     Map<String,String> map=new TreeMap<String,String>();        map.put("a","d");        map.put("b","c");        map.put("c","b");        map.put("d","a");        List<Map.Entry<String,String>> list = new ArrayList<>(map.entrySet());        Collections.sort(list,new Comparator<Map.Entry<String,String>>() {            //降序排序            public int compare(Map.Entry<String, String> o1,Map.Entry<String, String> o2) {                return o2.getValue().compareTo(o1.getValue());            }        });        for(Map.Entry<String,String> mapping:list){            System.out.println(mapping.getKey()+":"+mapping.getValue());        }

参考资料:
HashMap http://blog.csdn.net/vking_wang/article/details/14166593
ConcurrentHashMap http://blog.csdn.net/sherry_rui/article/details/51462549
代码实现双向链表
http://benjaminwhx.com/2016/01/18/Java%E5%AE%9E%E7%8E%B0%E5%8D%95%E5%90%91%E5%8F%8C%E5%90%91%E9%93%BE%E8%A1%A8%E5%8E%9F%E7%90%86%E5%88%86%E6%9E%90/

1 0
原创粉丝点击