怎样在手机中国地图带颜色上看啥颜色是带表啥道路来

搜狗地图地图|首页从到首页首页在很久很久以前,讲过,讲到Set就是Map的马甲,那么今天我们就来看看Map是如何实现的(本文都基于JDK1.8的版本)
Map和Collection有关的几个map的关系图
public interface Map&K, V&
An object that maps keys to values. A map cannot contain each key can map to at most one value.
This interface takes the place of the Dictionary class, which was a totally abstract class rather than an interface.
The Map interface provides three collection views, which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings. The order of a map is defined as the order in which the iterators on the map's collection views return their elements. Some map implementations, like the TreeMap class, make specific guarantees as to others, like the HashMap class, do not.
Map的三个特点
1.包含键值对
3.键对应的值唯一
Map还提供了3个集合视图,分别是一组键值对,一组键,一组值
Map有哪些方法
先来看看常量
* The default initial capacity - MUST be a power of two.
static final int DEFAULT_INITIAL_CAPACITY = 1 && 4;
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two &= 1&&30.
static final int MAXIMUM_CAPACITY = 1 && 30;
* The load factor used when none specified in constructor.
static final float DEFAULT_LOAD_FACTOR = 0.75f;
* The bin count threshold for using a tree rather than list for a
Bins are converted to trees when adding an element to a
* bin with at least this many nodes. The value must be greater
* than 2 and should be at least 8 to mesh with assumptions in
* tree removal about conversion back to plain bins upon
* shrinkage.
static final int TREEIFY_THRESHOLD = 8;
* The bin count threshold for untreeifying a (split) bin during a
* resize operation. Should be less than TREEIFY_THRESHOLD, and at
* most 6 to mesh with shrinkage detection under removal.
static final int UNTREEIFY_THRESHOLD = 6;
* The smallest table capacity for which bins may be treeified.
* (Otherwise the table is resized if too many nodes in a bin.)
* Should be at least 4 * TREEIFY_THRESHOLD to avoid conflicts
* between resizing and treeification thresholds.
static final int MIN_TREEIFY_CAPACITY = 64;
如果不指定初值的话,列表的长度就为16,默认加载因子为0.75,
再来看看成员变量
* The table, initialized on first use, and resized as
* necessary. When allocated, length is always a power of two.
* (We also tolerate length zero in some operations to allow
* bootstrapping mechanics that are currently not needed.)
transient Node&K,V&[]
这个就是列表
* Holds cached entrySet(). Note that AbstractMap fields are used
* for keySet() and values().
transient Set&Map.Entry&K,V&& entryS
这个是用于缓存节点
* The number of key-value mappings contained in this map.
transient int
已经用于的节点数量
* The number of times this HashMap has been structurally modified
* Structural modifications are those that change the number of mappings in
* the HashMap or otherwise modify its internal structure (e.g.,
* rehash).
This field is used to make iterators on Collection-views of
* the HashMap fail-fast.
(See ConcurrentModificationException).
transient int modC
这个是修改的次数
* The next size value at which to resize (capacity * load factor).
极限值,如果节点数大于这个值就需要扩容了,这个值的计算方式是capacity * load factor
* The load factor for the hash table.
final float loadF
加载因子,决定了节点数值大于当前总数的一定百分比时,扩容
接下来的是构造函数
public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity & 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity & MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor &= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
this.loadFactor = loadF
this.threshold = tableSizeFor(initialCapacity);
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR;
如果了解当前数据的量的话,建议规定HashMap的大小,减少扩容次数,提高性能
public HashMap(Map&? extends K, ? extends V& m) {
this.loadFactor = DEFAULT_LOAD_FACTOR;
putMapEntries(m, false);
这个是从已有的Map中生成一个新的Map,属于深拷贝
接下来看下get的实现
public V get(Object key) {
return (e = getNode(hash(key), key)) == null ? null : e.value;
final Node&K,V& getNode(int hash, Object key) {
Node&K,V&[] Node&K,V& first, int K
if ((tab = table) != null && (n = tab.length) & 0 &&
(first = tab[(n - 1) & hash]) != null) {
if (first.hash == hash &&
((k = first.key) == key || (key != null && key.equals(k))))
if ((e = first.next) != null) {
if (first instanceof TreeNode)
return ((TreeNode&K,V&)first).getTreeNode(hash, key);
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
} while ((e = e.next) != null);
return null;
顺便提下,解决哈希冲突的常见4种方法,1.开放地址,简单说就是如果当前当前坑被占了,就继续找下个坑 2.拉链法,也就是JDK中选择实现HashMap的方法,数组的每个项又是一个链表,如果哈希后发现当前地址有数据了,就挂在这个链表的最后 3.再哈希 选择多种哈希方法,一个不行再换下一个,知道有坑为止
4.建立公共溢出 就把所有溢出的数据都放在溢出表里
说完get,那就看看put
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node&K,V&[] Node&K,V& int n,
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
Node&K,V& K
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
else if (p instanceof TreeNode)
e = ((TreeNode&K,V&)p).putTreeVal(this, tab, hash, key, value);
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount &= TREEIFY_THRESHOLD - 1)
treeifyBin(tab, hash);
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
if (e != null) {
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldV
if (++size & threshold)
afterNodeInsertion(evict);
return null;
增删改查,还差一个删没讲
public V remove(Object key) {
return (e = removeNode(hash(key), key, null, false, true)) == null ?
null : e.value;
final Node&K,V& removeNode(int hash, Object key, Object value,
boolean matchValue, boolean movable) {
Node&K,V&[] Node&K,V& int n,
if ((tab = table) != null && (n = tab.length) & 0 &&
(p = tab[index = (n - 1) & hash]) != null) {
Node&K,V& node = null, K V
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
else if ((e = p.next) != null) {
if (p instanceof TreeNode)
node = ((TreeNode&K,V&)p).getTreeNode(hash, key);
if (e.hash == hash &&
((k = e.key) == key ||
(key != null && key.equals(k)))) {
} while ((e = e.next) != null);
if (node != null && (!matchValue || (v = node.value) == value ||
(value != null && value.equals(v)))) {
if (node instanceof TreeNode)
((TreeNode&K,V&)node).removeTreeNode(this, tab, movable);
else if (node == p)
tab[index] = node.
p.next = node.
afterNodeRemoval(node);
return null;
再来看看最核心的方法,如何计算得到hash code
static final int hash(Object key) {
return (key == null) ? 0 : (h = key.hashCode()) ^ (h &&& 16);
看懂这个方法首先需要明白^和&&&这个两个运算符号
^这个符号叫做异或运算符,两个操作数的位中,相同则结果为0,不同则结果为1
比如2^5=7 因为11
&&&这个符号叫做无符号右移,忽略符号位,空位都以0补齐
比如5&&&2 0101&&&2等于0001=1,5&&& 0101&&&1 0010=2
再来看下hash这个方法,先取key的hashcode,这个是个native的方法,然后再与右移16位的值取异或。
int h = "hello".hashCode()
System.out.println("result1 : "+ h)
System.out.println("result2 : "+ (h&&&16))
System.out.println("result3 : "+ (h^(h&&&16)))
result2 : 1513
最后再讲下之前提到的modCount的作用。
可以看到modeCount在put,get,remove这些值中被修改。然后在AbstractSet的几个子类KeySet和Values中的foreach中被用来比较
public final void forEach(Consumer&? super V& action) {
Node&K,V&[]
if (action == null)
throw new NullPointerException();
if (size & 0 && (tab = table) != null) {
int mc = modC
for (int i = 0; i & tab. ++i) {
for (Node&K,V& e = tab[i]; e != null; e = e.next)
action.accept(e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
在循环之前先记录modCount的值,如果循环结束之后这个值被改变了说明HashMap内部结构发生了变化,线程不安全了,就抛出异常,从而实现“fast-fail”机制
LinkedHashMap
从名字就可以看出LinkedHashMap继承于HashMap,它相比于HashMap内部多维护了一个双向列表,目的就是保证输入顺序和输出顺序一致,带来的劣势也很明显,性能的消耗大大提升。
首先先来看下相比于HashMap增加的几个成员变量
static class Entry&K,V& extends HashMap.Node&K,V& {
Entry&K,V& before,
Entry(int hash, K key, V value, Node&K,V& next) {
super(hash, key, value, next);
transient LinkedHashMap.Entry&K,V&
transient LinkedHashMap.Entry&K,V&
final boolean accessO
接着看下增删改查几个操作
不知道还记不记得在上面HashMap中讲到的put操作中调用了一个方法叫newNode
它在LinkedHashMap中被重写了
Node&K,V& newNode(int hash, K key, V value, Node&K,V& e) {
LinkedHashMap.Entry&K,V& p =
new LinkedHashMap.Entry&K,V&(hash, key, value, e);
linkNodeLast(p);
private void linkNodeLast(LinkedHashMap.Entry&K,V& p) {
LinkedHashMap.Entry&K,V& last =
if (last == null)
p.before =
last.after =
在生成一个新节点的时候,不光把它放到数组中,还把它放到双向链表的尾部。
看完了增,改再来看看查
public V get(Object key) {
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);
return e.value;
再看看3个HashMap中的空方法,在LinkedHashMap中如何实现
void afterNodeAccess(Node&K,V& e) {
LinkedHashMap.Entry&K,V&
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry&K,V& p =
(LinkedHashMap.Entry&K,V&)e, b = p.before, a = p.
p.after = null;
if (b == null)
if (a != null)
a.before =
if (last == null)
p.before =
last.after =
void afterNodeRemoval(Node&K,V& e) {
LinkedHashMap.Entry&K,V& p =
(LinkedHashMap.Entry&K,V&)e, b = p.before, a = p.
p.before = p.after = null;
if (b == null)
if (a == null)
a.before =
void afterNodeInsertion(boolean evict) {
LinkedHashMap.Entry&K,V&
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.
removeNode(hash(key), key, null, false, true);
到这基本就明白了LinkedHashMap特点和如何实现
在Android中LRU就是LinkedHashMap的简单包装类,有兴趣的可以看下
分析TreeMap之前,首先先来了解下NavigableMap和SortedMap这个两个接口
SortedMap从名字就可以看出,在Map的基础上增加了排序的功能。它要求key与key之间是可以相互比较的,从而达到排序的目的。怎么样才能比较呢?在之前的Set中提到了.实现了内部排序,这儿,就通过comparator来实现排序。
而NavigableMap是继承于SortedMap,目前只有TreeMap和ConcurrentNavigableMap两种实现方式。它本质上添加了搜索选项到接口,主要为红黑树服务。先来了解下它新增的几个方法
* 返回小于key的最大值的结点
Map.Entry&K,V& lowerEntry(K key);
* 返回小于key的最大值结点的key
K lowerKey(K key);
* 返回小于等于key的最大值结点
Map.Entry&K,V& floorEntry(K key);
* 返回小于等于key的最大结点的key
K floorKey(K key);
* 返回大于等于key的最小结点
Map.Entry&K,V& ceilingEntry(K key);
* 返回大于等于key的最小结点的key
K ceilingKey(K key);
* 返回大于key的最小结点
Map.Entry&K,V& higherEntry(K key);
* 返回大于key的最小结点的key
K higherKey(K key);
* 返回最小key结点
Map.Entry&K,V& firstEntry();
* 返回最大key结点
Map.Entry&K,V& lastEntry();
* 删除最小key结点
Map.Entry&K,V& pollFirstEntry();
*删除最大key结点
Map.Entry&K,V& pollLastEntry();
* 获取相反顺序的map
NavigableMap&K,V& descendingMap();
* 返回key的升序迭代器
NavigableSet&K& navigableKeySet();
* 返回key的降序迭代器
NavigableSet&K& descendingKeySet();
NavigableMap&K,V& subMap(K fromKey, boolean fromInclusive,
boolean toInclusive);
* 小于等于toKey的map
NavigableMap&K,V& headMap(K toKey, boolean inclusive);
* 大于等于key的map
NavigableMap&K,V& tailMap(K fromKey, boolean inclusive);
然后我们来看看TreeMap的实现
首先,TreeMap其实就是一颗红黑树
R-B Tree是一种二叉查找树,所有符合二叉查找树的特点, 对于树中的每一个节点,如果它有左子树,则左子树中所有节点的值不大于该节点值;如果它有右子树,则右子树中所有节点的值不小于该节点的值
它本身又有几个独特的特性
每个节点要么是红的,要么是黑的。
根节点是黑的。
每个叶节点(叶节点即指树尾端NIL指针或NULL节点)是黑的。
如果一个节点是红的,那么它的两个儿子都是黑的。
对于任一节点而言,其到叶节点树尾端NIL指针的每一条路径都包含相同数目的黑节点。
有了这些理论知识,我们再来看看TreeMap的源码
先看看节点的数据结构
private static final boolean RED
private static final boolean BLACK = true;
static final class Entry&K,V& implements Map.Entry&K,V& {
Entry&K,V&
Entry&K,V&
Entry&K,V&
boolean color = BLACK;
public boolean containsKey(Object key) {
return getEntry(key) != null;
final Entry&K,V& getEntry(Object key) {
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable&? super K& k = (Comparable&? super K&)
Entry&K,V& p =
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp & 0)
else if (cmp & 0)
return null;
final Entry&K,V& getEntryUsingComparator(Object key) {
@SuppressWarnings("unchecked")
Comparator&? super K& cpr =
if (cpr != null) {
Entry&K,V& p =
while (p != null) {
int cmp = cpr.compare(k, p.key);
if (cmp & 0)
else if (cmp & 0)
return null;
再来看看增
之前讲定义的时候就提到过,R-B Tree有一些特殊的性质,所以再插入新的节点后,仍需要保持这些性质,需要动态平衡
public V put(K key, V value) {
Entry&K,V& t =
if (t == null) {
compare(key, key);
root = new Entry&&(key, value, null);
modCount++;
return null;
Entry&K,V& parent;
Comparator&? super K& cpr =
if (cpr != null) {
cmp = cpr.compare(key, t.key);
if (cmp & 0)
else if (cmp & 0)
return t.setValue(value);
} while (t != null);
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
Comparable&? super K& k = (Comparable&? super K&)
cmp = k.compareTo(t.key);
if (cmp & 0)
else if (cmp & 0)
return t.setValue(value);
} while (t != null);
Entry&K,V& e = new Entry&&(key, value, parent);
if (cmp & 0)
parent.left =
parent.right =
fixAfterInsertion(e);
modCount++;
return null;
分析源码前,先补充点理论知识
插入有5种不同情况
1) 情况1:插入的是根节点。
原树是空树,此情况只会违反性质2。
对策:直接把此节点涂为黑色。
2) 情况2:插入的节点的父节点是黑色。
此不会违反性质2和性质4,红黑树没有被破坏。
对策:什么也不做。
3) 情况3:当前节点的父节点是红色且祖父节点的另一个子节点(叔叔节点)是红色。
此时父节点的父节点一定存在,否则插入前就已不是红黑树。与此同时,又分为父节点是祖父节点的左子还是右子,对于对称性,我们只要解开一个方向就可以了。 在此,我们只考虑父节点为祖父左子的情况。 同时,还可以分为当前节点是其父节点的左子还是右子,但是处理方式是一样的。我们将此归为同一类。
对策:将当前节点的父节点和叔叔节点涂黑,祖父节点涂红,把当前节点指向祖父节点,从新的当前节点重新开始算法。
情况4:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的右子
对策:当前节点的父节点做为新的当前节点,以新当前节点为支点左旋。
情况5:当前节点的父节点是红色,叔叔节点是黑色,当前节点是其父节点的左子
解法:父节点变为黑色,祖父节点变为红色,在祖父节点为支点右旋
private void fixAfterInsertion(Entry&K,V& x) {
x.color = RED;
while (x != null && x != root && x.parent.color == RED) {
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
Entry&K,V& y = rightOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
if (x == rightOf(parentOf(x))) {
x = parentOf(x);
rotateLeft(x);
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
Entry&K,V& y = leftOf(parentOf(parentOf(x)));
if (colorOf(y) == RED) {
setColor(parentOf(x), BLACK);
setColor(y, BLACK);
setColor(parentOf(parentOf(x)), RED);
x = parentOf(parentOf(x));
if (x == leftOf(parentOf(x))) {
x = parentOf(x);
rotateRight(x);
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateLeft(parentOf(parentOf(x)));
root.color = BLACK;
再来看下删除操作
private void deleteEntry(Entry&K,V& p) {
modCount++;
if (p.left != null && p.right != null) {
Entry&K,V& s = successor(p);
p.key = s.
p.value = s.
Entry&K,V& replacement = (p.left != null ? p.left : p.right);
if (replacement != null) {
replacement.parent = p.parent;
if (p.parent == null)
else if (p == p.parent.left)
p.parent.left
p.parent.right =
p.left = p.right = p.parent = null;
if (p.color == BLACK)
fixAfterDeletion(replacement);
} else if (p.parent == null) {
root = null;
if (p.color == BLACK)
fixAfterDeletion(p);
if (p.parent != null) {
if (p == p.parent.left)
p.parent.left = null;
else if (p == p.parent.right)
p.parent.right = null;
p.parent = null;
这里和增加一样需要动态调整,同样有几种不同的情况
情况1:当前节点是红+黑色
解法,直接把当前节点染成黑色,结束。此时红黑树性质全部恢复。
情况2:当前节点是黑+黑且是根节点
解法:什么都不做,结束
情况3:当前节点是黑+黑且兄弟节点为红色(此时父节点和兄弟节点的子节点分为黑)。
解法:把父节点染成红色,把兄弟节点染成黑色,之后重新进入算法(我们只讨论当前节点是其父节点左孩子时的情况)。此变换后原红黑树性质5不变,而把问题转化为兄弟节点为黑色的情况(注:变化前,原本就未违反性质5,只是为了把问题转化为兄弟节点为黑色的情况)。
情况4:当前节点是黑加黑且兄弟是黑色且兄弟节点的两个子节点全为黑色。
解法:把当前节点和兄弟节点中抽取一重黑色追加到父节点上,把父节点当成新的当前节点,重新进入算法。(此变换后性质5不变)
情况5:当前节点颜色是黑+黑,兄弟节点是黑色,兄弟的左子是红色,右子是黑色。。
解法:把兄弟节点染红,兄弟左子节点染黑,之后再在兄弟节点为支点解右旋,之后重新进入算法。此是把当前的情况转化为情况6,而性质5得以保持。
情况6:当前节点颜色是黑-黑色,它的兄弟节点是黑色,但是兄弟节点的右子是红色,兄弟节点左子的颜色任意。
解法:把兄弟节点染成当前节点父节点的颜色,把当前节点父节点染成黑色,兄弟节点右子染成黑色,之后以当前节点的父节点为支点进行左旋,此时算法结束,红黑树所有性质调整正确。
可以对应着看下
private void fixAfterDeletion(Entry&K,V& x) {
while (x != root && colorOf(x) == BLACK) {
if (x == leftOf(parentOf(x))) {
Entry&K,V& sib = rightOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateLeft(parentOf(x));
sib = rightOf(parentOf(x));
if (colorOf(leftOf(sib))
== BLACK &&
colorOf(rightOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
if (colorOf(rightOf(sib)) == BLACK) {
setColor(leftOf(sib), BLACK);
setColor(sib, RED);
rotateRight(sib);
sib = rightOf(parentOf(x));
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(rightOf(sib), BLACK);
rotateLeft(parentOf(x));
} else { // symmetric
Entry&K,V& sib = leftOf(parentOf(x));
if (colorOf(sib) == RED) {
setColor(sib, BLACK);
setColor(parentOf(x), RED);
rotateRight(parentOf(x));
sib = leftOf(parentOf(x));
if (colorOf(rightOf(sib)) == BLACK &&
colorOf(leftOf(sib)) == BLACK) {
setColor(sib, RED);
x = parentOf(x);
if (colorOf(leftOf(sib)) == BLACK) {
setColor(rightOf(sib), BLACK);
setColor(sib, RED);
rotateLeft(sib);
sib = leftOf(parentOf(x));
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), BLACK);
setColor(leftOf(sib), BLACK);
rotateRight(parentOf(x));
setColor(x, BLACK);
最后挑一个NavigableMap的导航方法看看,分析下如何实现
final Entry&K,V& getCeilingEntry(K key) {
Entry&K,V& p =
while (p != null) {
int cmp = compare(key, p.key);
if (cmp & 0) {
if (p.left != null)
} else if (cmp & 0) {
if (p.right != null) {
Entry&K,V& parent = p.parent;
Entry&K,V& ch =
while (parent != null && ch == parent.right) {
ch = parent;
parent = parent.parent;
return parent;
return null;
TreeMap&Integer, String& treeMap = new TreeMap&&();
treeMap.put(15, "15");
treeMap.put(7, "7");
treeMap.put(6, "6");
treeMap.put(9, "9");
treeMap.put(21, "21");
treeMap.put(17, "28");
treeMap.put(24, "24");
treeMap.put(30, "30");
System.out.print("key :
" + treeMap.ceilingEntry(20).getKey());
结果就是21
主要几个Map实现方式:HashMap,LinkedHashMap和Tree都进行了分析,对应的HashSet和TreeSet大家再回顾下Set章节里的内容一定会有一个更深的了解。还有一个很经典的ConcurrentHashMap等有时间再单独开一章节讲下,只要能把ConcurrentHashMap研究透了,你的多线程处理功夫就到家了,
对JAVA中Map的理解
在JAVA.util 中的集合类包含 Java 中某些最常用的类。
其中,最常用的集合类是 List 和 Map。
List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的...
Java Map 集合类简介
java.util 中的集合类包含 Java 中某些最常用的类。 最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适...
STL中map用法详解
Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候...
map容器的详细用法
map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候...
HashMap & Hashtable 区别a.HashMap不是线程安全的;HashTable是线程安全的,其线程安全是通过Sychronize实现。b.由于上述原因,HashMap...
Map 的4种遍历方式及比较
第一种方式:
keySet 其实遍历了两次,第一次获取Iterator,第二次根据key获取value,因此性能较差。
1. Map的四种遍历方式
下面只是简单介绍各种遍历示例(以HashMap为例),各自优劣会在本文后面进行分析给出结论。
(1) for each map.entrySet()
Map集合:该集合存储键(K)值(V)对,一对一往里存,而且要保证键的唯一性。
put(K key,V value)
流行的社交媒体平台可以迅速在众多人群中传播重要的社交网络信息。在本文中,我们提出了D-Map(扩散映射),一种新颖的视觉化方法,通过地图隐喻来支持在典型社交媒体上的信息传播和传播过程中对社会行为的探索...
SSD计算mAP值
https://github.com/weiliu89/caffe
3种计算方法:
参考文献:
https://sanchom.wordpress.com/tag/ave...
没有更多推荐了,}

我要回帖

更多关于 带颜色的手机壳 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信