1、TreeMap介绍

TreeMap是一个通过红黑树实现有序的key-value集合。

TreeMap继承AbstractMap,也即实现了Map,它是一个Map集合

TreeMap实现了NavigableMap接口,它支持一系列的导航方法,

TreeMap实现了Cloneable接口,它可以被克隆

TreeMap introduction:A Red-Black tree based NavigableMap implementation. The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time, depending on which constructor is used.
This implementation provides guaranteed log(n) time cost for the containsKey, get, put and remove operations. Algorithms are adaptations of those in Cormen, Leiserson, and Rivest’s Introduction to Algorithms.

TreeMap基于红黑树(Red-Black tree)实现。映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。TreeMap的基本操作containsKey、get、put、remove方法,它的时间复杂度是log(n)。--(翻译JDK中关于TeeMap简介)

TreeMap是非同步的。

TreeMap与Map的关系图如下:

TreeMap本质是Red-Black Tree,它包含几个重要的成员变量:root、size、comparator。其中root是红黑树的根节点。它是Entry类型,Entry是红黑树的节点,它包含了红黑树的6个基本组成:key、value、left、right、parent和color。Entry节点根据根据Key排序,包含的内容是value。Entry中key比较大小是根据比较器comparator来进行判断的。size是红黑树的节点个数。具体的红黑树算法,请自行百度。

2、TreeMap源码解析(JDK1.6版本)

为了更了解TreeMap的原理,下面我们将根据TreeMap中实现的方法来对源码做一个详细的说明。

2.1、TreeMap数据结构

TreeMap的定义如下:

public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable

 TreeMap继承AbstractMap,实现NavigableMap、Cloneable、Serializable三个接口。其中AbstractMap表明TreeMap为一个Map即支持key-value的集合, NavigableMap则意味着它支持一系列的导航方法,具备针对给定搜索目标返回最接近匹配项的导航方法 。

TreeMap中同时包含如下几个重要的属性:

/**
* The comparator used to maintain order in this tree map, or
* null if it uses the natural ordering of its keys.
* 比较器,用来给TreeMap排序
* @serial
*/
private final Comparator<? super K> comparator;
/**
* 红黑树的根节点
*/
private transient Entry<K,V> root = null; /**
* The number of entries in the tree
* 红黑树的节点总数
*/
private transient int size = 0; /**
* The number of structural modifications to the tree.
* 红黑树的修改次数
*/
private transient int modCount = 0; // Red-black mechanics
/**
* 红黑树的颜色--红色
*/
private static final boolean RED = false; /**
* 红黑树的颜色--黑色
*/
private static final boolean BLACK = true;

对于叶子节点Entry来说,Entry是TreeMap的内部类,它有几个重要属性:

static final class Entry<K,V> implements Map.Entry<K,V> {
//键
K key;
//值
V value;
//左孩子
Entry<K,V> left = null;
//右孩子
Entry<K,V> right = null;
//父亲
Entry<K,V> parent;
//颜色
boolean color = BLACK; /**
* Make a new cell with given key, value, and parent, and with
* <tt>null</tt> child links, and BLACK color.
*/
Entry(K key, V value, Entry<K,V> parent) {
this.key = key;
this.value = value;
this.parent = parent;
} /**
* Returns the key.
*
* @return the key
*/
public K getKey() {
return key;
} /**
* Returns the value associated with the key.
*
* @return the value associated with the key
*/
public V getValue() {
return value;
} /**
* Replaces the value currently associated with the key with the given
* value.
*
* @return the value associated with the key before this method was
* called
*/
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
} public boolean equals(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>)o; return valEquals(key,e.getKey()) && valEquals(value,e.getValue());
} public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
return keyHash ^ valueHash;
} public String toString() {
return key + "=" + value;
}
}

2.2、TreeMap的构造器

2.2.1、默认构造器

使用默认构造器构造TreeMap时,使用java的默认的比较器比较Key的大小,从而对TreeMap进行排序

/**
* Constructs a new, empty tree map, using the natural ordering of its keys.
* 默认构造器
*/
public TreeMap() {
comparator = null;
}

2.2.2、带比较器的构造函数

/**
* Constructs a new, empty tree map, ordered according to the given comparator.
* 给定比较器的构造函数
*/
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}

2.2.3、带Map的构造函数,Map会成为TreeMap的子集

/**
* Constructs a new tree map containing the same mappings as the given
* map
*/
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
}

该构造函数会调用putAll()将m中的所有元素添加到TreeMap中。putAll()源码如下 :

/**
* Copies all of the mappings from the specified map to this map.
* These mappings replace any mappings that this map had for any
* of the keys currently in the specified map.
* 将Map中的节点全部添加到TreeMap中
*/
public void putAll(Map<? extends K, ? extends V> map) {
int mapSize = map.size();
if (size==0 && mapSize!=0 && map instanceof SortedMap) {
Comparator c = ((SortedMap)map).comparator();
if (c == comparator || (c != null && c.equals(comparator))) {
++modCount;
try {
buildFromSorted(mapSize, map.entrySet().iterator(),
null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
return;
}
}
super.putAll(map);
}

2.2.4、带SortedMap的构造函数,SortedMap会成为TreeMap的子集

/**
* Constructs a new tree map containing the same mappings and
* using the same ordering as the specified sorted map. This
* method runs in linear time.
*/
public TreeMap(SortedMap<K, ? extends V> m) {
comparator = m.comparator();
try {
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}

带map参数的构造器都调用了buildFromSorted()。buildFromSorted()设计代码如下:

// 根据已经一个排好序的map创建一个TreeMap
// 将map中的元素逐个添加到TreeMap中,并返回map的中间元素作为根节点。
private final Entry<K,V> buildFromSorted(int level, int lo, int hi,
int redLevel,
Iterator it,
java.io.ObjectInputStream str,
V defaultVal)
throws java.io.IOException, ClassNotFoundException {
/*
* Strategy: The root is the middlemost element. To get to it, we
* have to first recursively construct the entire left subtree,
* so as to grab all of its elements. We can then proceed with right
* subtree.
*
* The lo and hi arguments are the minimum and maximum
* indices to pull out of the iterator or stream for current subtree.
* They are not actually indexed, we just proceed sequentially,
* ensuring that items are extracted in corresponding order.
*/ if (hi < lo) return null; int mid = (lo + hi) / 2; Entry<K,V> left = null;
if (lo < mid)
left = buildFromSorted(level+1, lo, mid - 1, redLevel,
it, str, defaultVal); // extract key and/or value from iterator or stream
K key;
V value;
if (it != null) {
if (defaultVal==null) {
Map.Entry<K,V> entry = (Map.Entry<K,V>)it.next();
key = entry.getKey();
value = entry.getValue();
} else {
key = (K)it.next();
value = defaultVal;
}
} else { // use stream
key = (K) str.readObject();
value = (defaultVal != null ? defaultVal : (V) str.readObject());
} Entry<K,V> middle = new Entry<K,V>(key, value, null); // color nodes in non-full bottommost level red
if (level == redLevel)
middle.color = RED; if (left != null) {
middle.left = left;
left.parent = middle;
} if (mid < hi) {
Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel,
it, str, defaultVal);
middle.right = right;
right.parent = middle;
} return middle;
}

对buildFromSorted方法解读

  • buildFromSorted是通过递归将SortedMap中的元素逐个关联
  • buildFromSorted返回middle节点作为root
  • buildFromSorted添加到红黑树中时,只将level == redLevel的节点设为红色。

2.3、TreeMap实现的Serializable接口

TreeMap实现了java.io.Serializable,分别实现了串行读取、写入功能。串行写入函数是writeObject(),它的作用是将TreeMap的容量,所有的Entry都写入到输出流。而串行读取函数是readObject(),它的作用是将TreeMap的容量,所有的Entry依次读出。通过readObject和writeObject能够帮助我们实现TreeMap的串行传输。

private static final long serialVersionUID = 919286545866124006L;

    /**
* Save the state of the <tt>TreeMap</tt> instance to a stream (i.e.,
* serialize it).
*
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
// Write out the Comparator and any hidden stuff
s.defaultWriteObject(); // Write out size (number of Mappings)
s.writeInt(size); // Write out keys and values (alternating)
for (Iterator<Map.Entry<K,V>> i = entrySet().iterator(); i.hasNext(); ) {
Map.Entry<K,V> e = i.next();
s.writeObject(e.getKey());
s.writeObject(e.getValue());
}
} /**
* Reconstitute the <tt>TreeMap</tt> instance from a stream (i.e.,
* deserialize it).
*/
private void readObject(final java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in the Comparator and any hidden stuff
s.defaultReadObject(); // Read in size
int size = s.readInt(); buildFromSorted(size, null, s, null);
}

2.4、TreeMap实现了Cloneable接口

TreeMap实现了Cloneable接口,即实现了clone()方法。clone()方法的作用很简单,就是克隆一个TreeMap对象并返回。

/**
* Returns a shallow copy of this <tt>TreeMap</tt> instance. (The keys and
* values themselves are not cloned.)
*
* @return a shallow copy of this map
*/
public Object clone() {
TreeMap<K,V> clone = null;
try {
clone = (TreeMap<K,V>) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError();
} // Put clone into "virgin" state (except for comparator)
clone.root = null;
clone.size = 0;
clone.modCount = 0;
clone.entrySet = null;
clone.navigableKeySet = null;
clone.descendingMap = null; // Initialize clone with our mappings
try {
clone.buildFromSorted(size, entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
} return clone;
}

2.5、TreeMap重要方法的实现原理

TreeMap继承AbstractMap,也即是一个Map。这里对map的主要方法做一个解析

2.5.1、TreeMap的put()方法实现原理

/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for the key, the old
* value is replaced.
*/
public V put(K key, V value) {
//用t表示二叉树的当前节点
Entry<K,V> t = root;
//t为null表示一个空树,即TreeMap中没有任何元素,直接插入
if (t == null) {
//将新的key-value键值对创建为一个Entry节点,并将该节点赋予给root
root = new Entry<K,V>(key, value, null);
size = 1;
//修改次数加1
modCount++;
return null;
}
//cmp表示key排序的返回结果
int cmp;
Entry<K,V> parent;
// 指定的排序算法
Comparator<? super K> cpr = comparator;
//如果cpr不为空,则采用给定的排序算法创建TreeMap集合
if (cpr != null) {
do {
parent = t;//parent指向上次循环后的t
cmp = cpr.compare(key, t.key);
//cmp返回值小于0,表示新增节点的key小于当前key的值,则以当前节点的左孩子作为新的当前节点
//否则,以当前节点的右孩子作为新的当前节点
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
//如果cpr为空,则采用默认的排序算法进行创建TreeMap集合
else {
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<K,V>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
//上面已经完成了排序二叉树的构建,将新增节点插入该树中的合适位置,下面fixAfterInsertion方法就是对这棵树进行调整、平衡
fixAfterInsertion(e);
size++;
modCount++;
return null;
}

上述代码中do代码块实现排序二叉树的核心算法,通过该算法我们可以确认新增节点在该树的正确位置。找到该位置后将插入即可,这样做其实还没有完成,因为我们知道TreeMap的底层实现是红黑树,红黑树是一个平衡排序二叉树,普通的排序二叉树可能会出现失衡的情况,所以下一步就是要进行调整。fixAfterInsertion(e); 调整的过程务必会涉及到红黑树的左旋、右旋、着色三个基本操作。代码如下:

/** From CLR */
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));
} else {
if (x == rightOf(parentOf(x))) {
x = parentOf(x);
rotateLeft(x);
}
setColor(parentOf(x), BLACK);
setColor(parentOf(parentOf(x)), RED);
rotateRight(parentOf(parentOf(x)));
}
} else {
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));
} else {
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;
}

这段代码中包含了左旋(rotateLeft())、右旋(rotateRight())和着色(setColor)等符合红黑树新增节点的处理过程。

2.5.2、TreeMap的remove()方法实现原理

/**
* Removes the mapping for this key from this TreeMap if present.
*
*/
public V remove(Object key) {
Entry<K,V> p = getEntry(key);
if (p == null)
return null; V oldValue = p.value;
deleteEntry(p);
return oldValue;
}

通过这段代码可以看出,TreeMap的remove()方法中执行删除的真正方式是deleteEntry()方法。deleteEntry()代码如下:

    /**
* Delete node p, and then rebalance the tree.
*/
private void deleteEntry(Entry<K,V> p) {
modCount++;//修改次数 +1;
size--;//元素个数 -1 // If strictly internal, copy successor's element to p and then make p
// point to successor.
/*
* 被删除节点的左子树和右子树都不为空,那么就用 p节点的中序后继节点代替 p 节点
* successor(P)方法为寻找P的替代节点。规则是右分支最左边,或者 左分支最右边的节点
* ---------------------(1)
*/
if (p.left != null && p.right != null) {
Entry<K,V> s = successor (p);
p.key = s.key;
p.value = s.value;
p = s;
} // p has 2 children // Start fixup at replacement node, if it exists.
//replacement为替代节点,如果P的左子树存在那么就用左子树替代,否则用右子树替代
Entry<K,V> replacement = (p.left != null ? p.left : p.right);
/*
* 删除节点,分为上面提到的三种情况
* -----------------------(2)
*/
//如果替代节点不为空
if (replacement != null) {
// Link replacement to parent
//replacement来替代P节点
replacement.parent = p.parent;
if (p.parent == null)
root = replacement;
else if (p == p.parent.left)
p.parent.left = replacement;
else
p.parent.right = replacement; // Null out links so they are OK to use by fixAfterDeletion.
p.left = p.right = p.parent = null; // Fix replacement
if (p.color == BLACK)
fixAfterDeletion(replacement);
} else if (p.parent == null) { // return if we are the only node.
root = null;
} else { // No children. Use self as phantom replacement and unlink.
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;
}
}
}

3、TreeMap的使用场景

我们了解了什么是TreeMap以及它的部分实现原理。那我们该如何运用treeMap呢?TreeMap是Map接口的具体实现,它的应用场景与Map应用场景大体相同。Map用于保存具有"映射关系"的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value。key和value都可以是任何引用类型的数据。Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较结果总是返回false。 关于Map,我们要从代码复用的角度去理解,java是先实现了Map,然后通过包装了一个所有value都为null的Map就实现了Set集合 Map的这些实现类和子接口中key集的存储形式和Set集合完全相同(即key不能重复) Map的这些实现类和子接口中value集的存储形式和List非常类似(即value可以重复、根据索引来查找) 。TreeMap通常比HashMap、Hashtable要慢(尤其是在插入、删除key-value对时更慢),因为TreeMap底层采用红黑树来管理键值对。但是TreeMap有一个好处就是:TreeMap中的key-value对总是处于有序状态,无须专门进行排序操作。并且虽然TreeMap在插入和删除方面性能比较差,但是在分类处理的时候作用很大,遍历的速度很快。TreeMap的使用示例

/**
* 该方法用于获得初始化成员变量sysbasecodeCache,调用remote接口,
* 获得所有的cbossBaseCode,并按code_type分
* 类,每一类编码存放在一个TreeMap中,并把所有生成的TreeMap作 为m_SysBaseTable的成员保存。
*
* @return void
* @throws
*/
public static void initSysBaseCode() throws CBossDataAccessException {
long start = System.currentTimeMillis();
CBossLogUtil.getLogger(BaseCodeHelper.class).info(">>开始缓存["+CbossBaseCodeDataModule.TABLE_NAME+"]数据...");
// 初始化前先清理缓存
cleancache();
int iCodeType = -999;
Map<String, CbossBaseCodeDataModule> treeMap = null;
Connection conn = null;
try {
conn = DataSourceProxy.getConnectionBySchema(CbossBaseCodeDataModule.SCHEMA_NAME);
CbossBaseCodeDAO basedao = new CbossBaseCodeDAO(conn);
List<CbossBaseCodeDataModule> baseCodes = basedao.selectAll();
for (CbossBaseCodeDataModule cbossBaseCode : baseCodes) {
iCodeType = cbossBaseCode.getCodeType();
treeMap = (TreeMap) sysbasecodeCache.get(new Integer(iCodeType));
if (treeMap == null) {
treeMap = new TreeMap<String, CbossBaseCodeDataModule>();
sysbasecodeCache.put(new Integer(iCodeType), treeMap);
}
treeMap.put(cbossBaseCode.getCodeId(), cbossBaseCode);
}
} catch (Exception e) {
throw new CBossDataAccessException(e.getMessage() + "基础代码初始化时出现异常");
} finally {
DataSourceProxy.closeConnection(conn);
CBossLogUtil.getLogger(BaseCodeHelper.class).info(">>["+CbossBaseCodeDataModule.TABLE_NAME+"]数据缓存完成, cost("+(System.currentTimeMillis() - start)+")ms");
}
}

在遍历TreeMap的时候,能够直接确定分类,然后在分类中遍历,最终能够以最快的速度获取想要的结果。

TreeMap源码解析的更多相关文章

  1. 给jdk写注释系列之jdk1.6容器(7)-TreeMap源码解析

    TreeMap是基于红黑树结构实现的一种Map,要分析TreeMap的实现首先就要对红黑树有所了解.      要了解什么是红黑树,就要了解它的存在主要是为了解决什么问题,对比其他数据结构比如数组,链 ...

  2. Java - TreeMap源码解析 + 红黑树

    Java提高篇(二七)-----TreeMap TreeMap的实现是红黑树算法的实现,所以要了解TreeMap就必须对红黑树有一定的了解,其实这篇博文的名字叫做:根据红黑树的算法来分析TreeMap ...

  3. Java TreeMap 源码解析

    继上篇文章介绍完了HashMap,这篇文章开始介绍Map系列另一个比较重要的类TreeMap. 大家也许能感觉到,网络上介绍HashMap的文章比较多,但是介绍TreeMap反而不那么多,这里面是有原 ...

  4. TreeMap源码解析笔记

    常见的数据结构有数组.链表,还有一种结构也很常见,那就是树.前面介绍的集合类有基于数组的ArrayList,有基于链表的LinkedList,还有链表和数组结合的HashMap,今天介绍基于树的Tre ...

  5. Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例

    概要 这一章,我们对TreeMap进行学习.我们先对TreeMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeMap.内容包括:第1部分 TreeMap介绍第2部分 TreeMa ...

  6. TreeMap详细介绍(源码解析)和使用示例

    本文转自 http://www.cnblogs.com/skywang12345/p/3310928.html 概要 这一章,我们对TreeMap进行学习.我们先对TreeMap有个整体认识,然后再学 ...

  7. 【转】Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例

    概要 这一章,我们对TreeMap进行学习.我们先对TreeMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeMap.内容包括:第1部分 TreeMap介绍第2部分 TreeMa ...

  8. 给jdk写注释系列之jdk1.6容器(8)-TreeSet&NavigableMap&NavigableSet源码解析

    TreeSet是一个有序的Set集合. 既然是有序,那么它是靠什么来维持顺序的呢,回忆一下TreeMap中是怎么比较两个key大小的,是通过一个比较器Comparator对不对,不过遗憾的是,今天仍然 ...

  9. Java 集合系列17之 TreeSet详细介绍(源码解析)和使用示例

    概要 这一章,我们对TreeSet进行学习.我们先对TreeSet有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeSet.内容包括:第1部分 TreeSet介绍第2部分 TreeSe ...

随机推荐

  1. 解决Ubuntu和Windows的文件乱码问题(转载)

    解决Ubuntu和Windows的文件乱码问题(debian也通用) 1.转换文件内容编码   Windows下天生的纯文本文件,其中文编码为GBK,在Ubuntu下显示为乱码,可以使用iconv命令 ...

  2. 顺序表 C++模板实现

    #include <iostream> using namespace std; template <typename T> class list{ private: int ...

  3. Web前端新人笔记之jquery选择符

    jquery利用了CSS选择符的能力,让我们能够在DOM中快捷而轻松的获取元素或元素集合.本章将介绍以下内容: 1.网页中的元素结构: 2.如何通过CSS选择符在页面中查找元素: 3.扩展jquery ...

  4. 003.XE3包含了TPerlRegEx的单元

    使用'|'替换所有的内容 代码: program Project1; {$APPTYPE CONSOLE} uses System.SysUtils, System.RegularExpression ...

  5. splay学习笔记

    伸展树(Splay Tree),也叫分裂树,是一种二叉排序树,它能在O(log n)内完成插入.查找和删除操作.(来自百科) 伸展树的操作主要是 –rotate(x) 将x旋转到x的父亲的位置 voi ...

  6. simplest_dll 最简dll的创建与隐式调用(显式调用太麻烦,个人不建议使用)

    首先需要有个头文件,名字随便写  假设test.h //test.h #ifndef _TEST_H #define _TEST_H #ifdef TEST_EXPORTS //通过宏定义控制是输入还 ...

  7. codeforces 392A Blocked Points

    我的方式是用暴力的方法找到每一行每一列的边界点: 但是有大神直接用一个公式解决了:floor(n*sqrt(2))*4: 想了很久还是不理解,求各路大神指点! #include<iostream ...

  8. Hadoop新版本中map任务待处理split大小的计算方法

    1. split大小的计算公式 minSize=max{minSplitSize,mapred.min.split.size} (minSplitSize大小默认为1B) maxSize=mapred ...

  9. POJ 2983 Is the Information Reliable?(差分约束系统)

    http://poj.org/problem?id=2983 题意:N 个 defense stations,M条消息,消息有精确和模糊之分,若前边为P.则为精确消息,有两个defense stati ...

  10. 李洪强实现横向滚动的View<二>

    上一节中我们已经实现了一个带有图片,标题和价格label 的UIView 这节我们用这个view实现一个横向滚动的UIcollectionView 实现的效果如下:  01 - 创建CFTyreScr ...