集合、数据结构、时间复杂度

1、集合

1.1 概述

java集合分为三种类型,List、set和Map。List有序,可以重复。Set无序不重复。Map是Key-value对类型,其中Key具有set的特点。

1.2 List

List java中有ArrayList和LinkedList两种实现。

  • ArrayList
    通过数组来实现,擅长读操作,有容量概念,扩容发展50%。
  • LinkedList
    内部通过链表实现,通过指针实现,检索的对象时从两头检索,看索引位于哪个半段范围中。内部存放了首尾两个节点,元素通过node连接在一起。Node由item 、 prev、 next构成,检索最坏情况不会超过半数。
  • 性能评测

Arraylist

LinedList

结论

写(100w)

90,255ms

40ms

200x

读(5wth)

0.036,538ms

0.637,157ms

20x

1.3 Map

map是通过key-value关联起来的映射构成的集合。其中key具有set的特点。java中Map有HashMap和TreeMap。

  • HashMap
  1. 内部通过数组+链表实现
class HashMap{
  //
  transient Node<K,V>[] table;
  //
  static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
  }
}
class HashMap{
  //
  transient Node<K,V>[] table;
  //
  static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
  }
}
  1. Hashmap put流程为
int newhash = 获取key的新hash;
通过新hash定位桶的坐标;
if(坐标位为空?){
  在该位置创建节点 ;
}
else{
  if(新hash相同?){
   if(key是同一对象?){
       key相同,覆盖value的值。
   }
   else{
       if(key的equals是否相同?){
           key相同,覆盖value
       }
       else{
           继续寻找下一个Node;
       }
   }
  }
  else{
   继续找下一个Node;
  }
}
int newhash = 获取key的新hash;
通过新hash定位桶的坐标;
if(坐标位为空?){
  在该位置创建节点 ;
}
else{
  if(新hash相同?){
   if(key是同一对象?){
       key相同,覆盖value的值。
   }
   else{
       if(key的equals是否相同?){
           key相同,覆盖value
       }
       else{
           继续寻找下一个Node;
       }
   }
  }
  else{
   继续找下一个Node;
  }
}
  1. 新hash计算方法
    旧hash码的高低16位做异或运算,实现计算结果的更加分散,高位右移是想让更多的特征值参与进来。
static final int hash(Object key) {
  int h;
  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
static final int hash(Object key) {
  int h;
  return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
  • TreeMap
    内部通过红黑二叉树实现,具体见我的数据结构一文。

作业

  1. 设计一个类Person含有height、weight、age和blood是整数属性,实现hashcode方法,将四个属性编排到一个整数中作为hashcode.
    答:
class Person{
 private int height ;
     private int weight ;
     private int age ;
     private int blood ;

     public int hashCode(){
     return (height & 0xff) << 24
                 | (weight & 0xff) << 16
                 | (age & 0xff) << 8
                 | (blood & 0xff) << 0 ;
    }

     public boolean equals(Object o){
     if(o == null || o.getClass() != Person.class)
          return false ;
         return this.hashCode() == o.hashCode() ;
    }
}
class Person{
 private int height ;
     private int weight ;
     private int age ;
     private int blood ;

     public int hashCode(){
     return (height & 0xff) << 24
                 | (weight & 0xff) << 16
                 | (age & 0xff) << 8
                 | (blood & 0xff) << 0 ;
    }

     public boolean equals(Object o){
     if(o == null || o.getClass() != Person.class)
          return false ;
         return this.hashCode() == o.hashCode() ;
    }
}
  1. 折半查找的时间复杂度问题
    折半查找的时间复杂度为\(O(log_{2}n)\),具体过程见时间复杂度一文。
  2. 99乘法表的时间复杂度
    99乘法表的时间复杂度为\(O(n^2)\)
  3. 两个n阶方阵的乘积的时间复杂度
    两个n阶方阵的乘积的时间复杂度为\(O(n^3)\)
  4. 红黑树依次存放1,2,3,4,5,6,7,8做为key,给出树的最终结构。
    树结构为: