Android知识点总结(一):算法和数据结构汇总

156 阅读8分钟

1、请说一下HashMap,SparseArray原理,及优缺点。另外ConcurrentHashMap如何实现线程安全?

hashmap的原理

  • hashmap内部是一个默认容量为16的数组。数组每个元素又是一个链表头节点jdk1.8以后,达到指定数量之后,链表会转化为红黑树
  • 当为hashmap里put数据时,达到一定容量限制就自动扩容。当达到容量的0.75(扩容因子)之后。就扩容到2倍。然后重新hash
  • 增:先计算key的hash(装箱拆箱)每个key都会 hash&(当前数组容量-1),然后看适合放在哪个数组的链表上。
  • 查:先计算key的hash(装箱拆箱),找到hash值找到数组的位置,再遍历链表,找到对应的节点
  • 删除:同理查
  • 哈希冲突?没事,先比较哈希再比较key。双重保险。
  • Java8以前头插法,java8 尾查法

sparseArray的原理

  • sparseArray比hashmap更加省内存,某些条件下性能更好,主要避免了对key额自动装箱(int转为integer)。默认容量为0,不是10建议容量1000一下使用

  • 内部时两个数组,一个存key,用来定位,一个存value。key只能时int类型。查找方便,插入可能就麻烦,因为可能移动数组。

  • 增:扩容逻辑,size或以上时,小于等于4则为8,否则扩容到2倍

    • 存储容量大小为4或者8,会放入缓存中
  • 查:key数组时有序的,通过二分查找来定位Key数组种对应值的位置

  • 删:使用数组就要面临删除数据时数据搬移的问题,引入了delete标记,减少删除数据时造成的搬运,以此做到O(1).查找到delete标记时,表示数据已被删除

    • 因为delete为了做到删除O(0),但会影响空间,所以就有GC机制,当和size相关操作,以及和数组扩容相关操作,都会有道gc来清除delete标记的数据和index。
  • 装箱和拆箱:SparseArray的设计目标是节约内存空间,所以用给基本数据类型,因为比类更省空间。

  • 其实用到二分查找所以保证key有序,基本数据类型比对大小也很方便。

  • 有序度。例如 1 2 3 4 就被称为满有序度,而相反的 4 3 2 1 则被称为满逆序度。如果满有序度就直接用append加载后面比put会更有效率

  • 省内存,也就是和hashmap比

    • hahsmap最多用75%(为了防止都在一个链条上),sparearray可以挤满。
    • hashmap相比与sparseArray的属性变量之多不少。SparseArray从头到尾就两个数组

hashmap和sparseArray的优缺点

  • 内存空间使用率:1、sparseArray不用装箱 2、sparseArray而且数组可用满

  • 查询效率:1、当数据量大时,hashMap比SparseArray更快。

  • 插入效率:1、正序插入,sparseArray强。2、倒叙插入hashmap强

  • key的兼容性:sparsearray 的key要int,hashmap的key能hash就行

  • 使用场景:要省内存空间、key为int、数量少于1000。用sparseArray。否则用hashmap。

  • hashMap和SparseArray都是存储key-value类型数据

    • 数据结构:方面 hashMap是数组+链表+红黑树。SparseArray用的双数组
    • 性能:Hashmap默认是16个长度,会自动装箱,key是int的话,hashmap就要先封装成Integer。SparseArray用的限制是key是int。数量小于1k。如果key不是int,也小于1k。建议用Arraymap。Array有两个数组,一个存储index,一个存储key和value。

ConcurrentHashMap如何实现线程安全

  • jdk1.7锁的时Segment,一个segment包含多个HashEntry。jdk 1.8锁的颗粒度就是HashEntry
  • 使用了synchronized。

2、请说一说HashMap原理,存取过程,为什么用红黑树,红黑树与完全二叉树对比

  • hashmap内部是靠数组+链表或者红黑树维护。每个链表头存在数组里。jdk1.8 当链表长度大于等于8,就把链表转为红黑树。红黑树长度小于等于6以后,又变为链表。
  • 之所以用红黑树是因为查询效率高。时间复杂度是O(logN),链表是O(N)
  • 完全二叉树是除去最后一层是满二叉树,最后一层从左到右分布是完全二叉树
  • 红黑树是平衡二叉树的一种。相比于普通二叉树,极端情况会成一个线性结构,和链表一样了,没意义。
  • 平衡二叉树左右高度不会超过1,红黑树最长路径不会超过最短的两倍。虽然事件复杂度都是O(logN),但平衡二叉树会更快。
  • 插入删除操作,平很二叉树需要大量旋转来维持平衡。红黑树,通过改变颜色和旋转就好了。虽然复杂度都是O(logN),但明显红黑树更快。

3、请说一下hashmap put()底层原理,发生冲突时,如何去添加

  • 对key的hashCode()进行hash后计算数组下标index
  • 如果table为null,则resize初始化
  • 没碰撞直接放到对应下标的bucket
  • 碰撞了,找节点,先比hash(key)后比key。替换value
  • 如果是树结构就挂在树上。
  • 如果是链表,判断长度,加上新put的内容,长度大于等于8就转为树。
  • 数据put后,如果达到或者超过扩容因子之后。resize重新弄hash,重构hashmap

4、arraylist如何保证线程安全?

  • 在写个类继承arrayList,在重写各个方法上加synchronized关键字
  • 在arraylist的各个方法里可重入锁,ReentrantLock
  • 用Collection.SynchronizedList实现
  • 用CopyOnWriteArrayList类。多读少些。因为写时拷贝。

image.png

5、请说一下ArrayList\LinkedList\HashMap\LinkedHashMap的底层原理

  • ArrayList内部维护一个Object数组,初始大小为10,容量不足时扩展为1.5倍。找第N个元素,按照 数组很快,增删就慢了,因为要移动数组。
  • LikedList内部维护一个双向链表,好处时不用扩容,查第N个元素事件 复杂度为O(N),比Arraylist慢。增删只要改链表就好了很快
  • hashmap内部时数组+链表+红黑树的结构。初始容量为16,增长因子0.75。达到增长因子之后就扩容。数组遍历出来是无顺序的
  • linkedhashmap在hashmap的基础上,遍历出来时有序的。单项链表保存数据,另外实现了双向链表记录迭代顺序,迭代顺序可以是插入顺序或者是访问顺序(类似LRU)

image.png

5.1、LinkedList和ArrayList的区别

  • LinkedList是双向链表,ArrayList是可变数组
  • LinkedList不允许随机访问,查询效率低,ArrayList允许随机访问,查询效率高
  • linkedList插入\删除快。ArrayList插入、删除慢

6、请说一下HashMap实现原理,扩容条件,链表转红黑树的条件。

  • hashmap底层维护了一个数组,默认16,数组元素是链表头或者红黑树根节点。
  • hashmap存入 和内容是key value。如果是存的null key,存在下标为0的桶。否则时候将hash(key)&(数组长度-1),找到适合的下标,如果桶里没东西,直接存入,否则先遍历,有了就覆盖,没有的话,jdk8以前是插在链头,然后把链表头放到桶里。jdk8是尾插法,放到尾部。
  • 扩容条件是hashmap元素数达到增长因子hashmap bucket数的0.75时,就扩容干一倍数 ,不超过int最大值。准确说道道2^30就不会增长了
  • 链表转红黑树的条件。当链表长度大于等于8就转红黑树,纪律很小千分之6还是8。小于等于6就转回来。

7、请说一下二叉树遍历的遍历步骤

  • 二叉树就是,有序树,并且各个节点的度不能超过2. image.png

深度优先(根是一条斜线),有空用非递归写一下

  • 前序遍历 根左右
void bianli(struct TreeNode* root){
    //根
    if(!root) return;
    printf("%d\n",root->data);
    //左
    bianli(roor->leftchild);
    //右
    bianli(roor->rightchild);
}
  • 中序遍历 左根右//同理
  • 后序遍历 右左根//同理

广度优先

  • 层次优先遍历
void bianli(TreeNode root){
     Queue<TreeNode> queue = new ArrayDeque<>();
     quque.add(root);
     while(!queue.isEmpty()){
         TreeNode node = queue.poll();
         System.our.println(node.value);
         if(node.left!= null){
             queue.add(node.left);
         }
         if(node.right!=null){
             queue.add(node.right);
         }
     }
}

9、对称加密和非对称加密,MD5的原理

  • 对称加密就是加密端和解密端用的同一套秘钥,作为私钥。可能被拦截,客户端永远是不安全的。比如DES,3DES,AES.
  • 非对称加密,机密和解密用的不同秘钥,公钥加密信息,私钥解密。密钥在服务端非常安全。比如RSA和ECC
  • MD5 128位,其中4位组成一个16进制字符。所以我们看到的是32个16进制的字符组成的字符串。
    • md5基本不可逆运算,为什么基本呢?用户用彩虹表

    • 对所有的数据加密结果都是32位长字符

    • 同数据,加密同结果

    • 不同数据推成同MD5是很困难的,已经元数据和md5,想伪造不同数据有md5是非常困难的