三大语言(C/Java/Python)基本数据类型大小 / 内置容器 总结

三大语言(C/Java/Python)基本数据类型大小 / 内置容器 总结

@Author Luzhuo (http://luzhuo.me/blog)

关于为什么选这三门语言:
Java: 我是做移动开发的, 必选项;
C: 追求极致的速度, C必选;
Python: 快速开发, 不二之选.

基本数据类型

这张表格中, C的字节数大小是最重要的, 因为C能通过指针直接修改某类型的部分值, 而类型大小同时决定了指针的步长.

Java数据类型 Java字节数 C数据类型 C字节数(win32位系统) Python数据类型 Python字节数
boolean 1bit - - bool -
byte 1 - - - -
char 2 char 1 chr -
short 2 short 2 - -
int 4 int 4 int -
long 8 long 4 - -
- - long long 8 - -
float 4 float 4 float -
double 8 double 8 - -
- - - - complex -
string - - - str -

注:

  1. 以上表格的字节数的单位均为Byte类型, 除非特殊标注, 如1bit
  2. C的基本类型数据字节数比较特殊, 在32位操作系统和62为操作系统上, Win vc12 和 Linux gcc5.3.1 上的表现均不同.
  3. C分为 有符号类型(signed int) 和 无符号类型(unsigned int).
  4. Java的所有类型均为有符号类型.
  5. 1Byte = 8bit, 内存中的数据从右往左看.
  6. Python是弱类型语言, 字节数不是重点, 在C会自动转换数据类型

内置容器

结构组合 C Java Python 特点
数组 vector ArrayList(Vector/CopyOnWriteArrayList) list 动态数组, 查询快O(1),增删慢O(n)
数组+数组 deque - - 双端查询增删都快O(1), 不支持中间段操作
数组+数组 stack - - FILO(先进后出), 默认使用deque容器, 使用尾部
数组+数组 queue - - FIFO(先进先出), 默认使用deque容器, 尾部入头部出
数组式二叉树 priority_queue - - 最高级先出, 头部查询快O(1), 增删一般O( log ⁡ 2 N \log_{2}N log2N), 不支持中间段操作, 默认vector容器(实现Heap(完全二叉树)), 尾部入尾部出
链表 list LinkedList - 双向循环链表, 增删快O(1), 查询慢O(n)
链式二叉树 set TreeSet - 有序, 不重复, 查询增删都一般O( log ⁡ 2 N \log_{2}N log2N), 使用RBTree容器(链式实现)
链式二叉树 multiset - - 有序, 可重复, 查询增删都一般O( log ⁡ 2 N \log_{2}N log2N), 使用RBTree容器(链式实现)
链式二叉树 map TreeMap - 有序, key不重复, 查询增删都一般O( log ⁡ 2 N \log_{2}N log2N), 使用RBTree容器(链式实现)
链式二叉树 multimap - - 有序, key可重复, 查询增删都一般O( log ⁡ 2 N \log_{2}N log2N), 使用RBTree容器(链式实现)
数组+链表 hash_set HashSet - 无序(Hash分桶), 不重复, 查询增删都慢O(n), 使用HashTable容器(vector+list(桶)实现, 开链法)
数组+链表 hash_multiset - - 无序(Hash分桶), 可重复, 查询增删都慢O(n), 使用HashTable容器(vector+list(桶)实现, 开链法)
数组+链表 hash_map HashMap(Hashtable/ConcurrentHashMap) - 无序(Hash分桶), key不重复, 查询增删都慢O(n), 使用HashTable容器(vector+list(桶)实现, 开链法)
数组+链表 hash_multimap - - 无序(Hash分桶), key可重复, 查询增删都慢O(n), 使用HashTable(vector+list(桶)实现, 开链法)
- - - - -
数组 - (Stack) - FILO(先进后出), 增删查尾部都快O(1), 不支持中间段操作, 默认使用(Vector)容器, 使用尾部
数组 - ArrayDeque - 双端数组, 增删查头尾指针都快O(1), 不支持中间段操作, 添加元素时头尾指针分别往中间夹
数组*2 - EnumMap - 双数组, 分别存key,value, 增删查都快O(1), key必须为枚举类型
数组 - IdentityHashMap - 数组, 增删查较快O(k), key, value分别在+0, +1位置
数组+链表 - LinkedHashMap - 插入顺序 / 访问顺序(LRU), 在HashMap的Node上多加两个指针, 形成双向循环链表保证元素有序, LRU访问将结点移至链尾
数组+链表 - LinkedHashSet - 插入顺序, 直接使用LinkedHashMap
数组+链表 - WeakHashMap - 插入顺序, key无引用将自动GC, 使用HashTable实现
链式SkipList - (ConcurrentSkipListMap) - 有序, key不重复, 增删查一般O( log ⁡ 2 N \log_{2}N log2N), CAS, 并发安全, 使用SkipList实现(链式), 可代替TreeMap的安全并发
链式SkipList - (ConcurrentSkipListSet) - 有序, 直接使用 ConcurrentSkipListMap, 可代替TreeSet的安全并发
数组 - (CopyOnWriteArraySet) - 插入顺序, 增删查都慢O(n), 直接使用CopyOnWriteArrayList, 可代替HashSet的安全并发
链表 - (ConcurrentLinkedDeque) - 双向循环链表, 顶部增删查O(1), 不支持中间段访问, CAS, 可代替ArrayDeque的安全并发
链表 - (LinkedTransferQueue) - 单向循环链表, SynchronousQueue(直接给) + LinkedBlockingQueue(有缓冲队列), 并发安全的队列
数组 - (ArrayBlockingQueue) - 循环数组, 容量很小, 有缓冲区, 并发安全的队列
链表 - (LinkedBlockingQueue) - 单向循环链表, 容量很大, 有缓冲区, 并发安全的队列
数组式二叉树 - PriorityQueue(PriorityBlockingQueue) heapq(queue.PriorityQueue) 最低级先出, 增删一般O( log ⁡ 2 N \log_{2}N log2N), 动态(Heap完全二叉树)数组, 有缓冲区, 尾入头出, 并发安全
数组式二叉树 - (DelayQueue) - 可延迟的队列, 直接使用PriorityQueue, 并发安全(ReentrantLock)的队列
- - (SynchronousQueue) - 无缓冲的队列, 直接放直接给, 并发安全的队列
- - - - -
数组 - - dict 无序, key不重复, 增删查O(k), 使用HashTable, 开放定址法
数组 - - set 无序, key不重复, 增删查O(k), 使用HashTable, 开放定址法
数组 - - tuple 原序, 容量不变, 查O(1), 不支持增改
链表 - - (deque) 双向循环链表, 增删O(1), 查O(n), 线程安全, 充当队列
链表 - - (queue.Queue) FIFO(先进先出)队列, 直接使用deque, 尾入头出
数组 - - (queue.LifoQueue) LIFO(后进先出)队列, 直接使用list, 使用尾部

Java中非线程安装的结构可转为线程安全的结构

Map<E> map = Collections.synchronizedMap(new HashMap<E>());
List<E> list = Collections.synchronizedList(new ArrayList<E>());

Java并发替代容器

非并发容器 并发容器 安全原理
ArrayList CopyOnWriteArrayList ReentrantLock + arraycopy
ArrayDeque ConcurrentLinkedDeque CAS(sun.misc.Unsafe)
TreeMap ConcurrentSkipListMap SkipList的CAS(sun.misc.Unsafe)
TreeSet ConcurrentSkipListSet 直接使用 ConcurrentSkipListMap
HashMap ConcurrentHashMap 分段锁(synchronized加在hash元素对象上)
HashSet CopyOnWriteArraySet 直接使用CopyOnWriteArrayList, 去重由(遍历O(n)所有元素, 存在则不添加)实现

Java的队列

结构组合 Java 特点
数组式二叉树 PriorityQueue(PriorityBlockingQueue) 优先级队列
链表 (LinkedTransferQueue) 高效率队列, SynchronousQueue+LinkedBlockingQueue
数组 (ArrayBlockingQueue) 循环数组队列(容量小)
链表 (LinkedBlockingQueue) 单向循环链表队列(容量大)
数组式二叉树 (DelayQueue) 可延迟的队列, 直接使用PriorityQueue
- (SynchronousQueue) 无缓冲的队列

注:

  1. priority_queue为什么不是头部出, 因为要被删除的元素先被移到尾部, 再弹出,
  2. HashTable的增删查为什么不是O(1), 因为发生hash碰撞就是O(n)
  3. Java()内的结构为同步结构, 也就是线程安全的.
  4. JDK1.8+会将与HashTable相关容器的链表, 在过长时会转为RBTree
  5. HashSet直接使用HashMap来存储key, TreeSet直接使用TreeMap来存储key, 所以可认为他们分别为同一个东西.
  6. LinkedHashSet虽然直接使用LinkedHashMap来存储key, 但并未启用LRU (dummy占位)
  7. WeakHashMap的特性非常适合做缓存, 无引用将被自动GC.
  8. 分段锁, 对hash数组分段的锁, 实现的线程安全比原始线程安全的效率高, 比如ConcurrentHashMap比Hashtable效率高. (JDK1.8不再分段, 直接对hash元素加锁)
  9. 注意Java的容器Hashtable(小写的t)和结构HashTable(大写的T)的区别.
  10. 优先队列, C++的priority_queue最高级先出, Java的PriorityQueue最低级先出.
  11. EnumMap 的数组为什么增删查都是O(1)呢? 因为key数组按key值索引添加, value值按key值增加, 删除将value置为null, key保留, 不存在移动, 查询按key值查.
  12. IdentityHashMap, 一个数组同时存放key,value, key放在偶数位, value放在奇数位, hash碰撞看key的内存地址值, 相同覆盖, 不同将hash+2; 删除, 将key,value置为null
  13. Python的容器, 不管是list, dict, 还是tuple 等等, 用完之后都会缓存起来以备下次使用, 而不是销毁.
  14. 开放定址法: 在hash的基础上再hash.
  15. 再哈希法: 根据key使用不同的哈希函数生成多个hash.

你可能感兴趣的:(java)