B 树/B-树(B-Tree/Bee Tree)

作者:disappearedgod
时间:2014-5-9


前记


本文还是主要根据教材来进行书写《数据结构与算法》 Adam Drozdek的C++版本,代码还是用Java的较好一些。后来插入了普林斯顿大学的cousera课程“Algorithm”中的PDF。
这篇博客是“多叉树”中的B树这一段文字,由于字数偏多故而分离出来

正文

1.4.1 B 树

1.4.1.0 介绍
B树是是红黑树的一种实用性应用(partical applications)。
参考《算法》第四版中B-Tree的建立依靠了Page API,可以建立一个很大的树。如下图


1.4.1.1 定义及应用

B树(B-tree)是有Bayer和McCreight在1972年提出的数据结构。(他们也同时提出了数据库的索引,1972)
B树索引是数据库中存取和查找文件(称为记录或键值)的一种方法,应用于磁盘读取方面

B树(B-tree)是一种树状数据结构,它能够存储数据、对其进行排序并允许以O(log n)的时间复杂度运行进行查找顺序读取插入删除的数据结构。B树,概括来说是一个节点可以拥有多于2个子节点的二叉查找树。与自平衡二叉查找树不同,B-树为系统最优化大块数据的读和写操作。B-tree算法减少定位记录时所经历的中间过程,从而加快存取速度。普遍运用在数据库和文件系统。

<Algorithms 4th Edition>
Definition.A B-tree of order M (where M is an even positive integer) is a tree that
either is an external k-node (with k keys and associated information) or comprises
internal k-nodes (each with k keys and k links to B-trees representing each of the k
intervals delimited by the keys), having the following structural properties: every
path from the root to an external node must be the same length ( perfect balance);
and k must be between 2 and M 1 at the root and between M/2 and M 1 at
every other node.


1.4.1.2 一些性质

根据Knuth's的定义,m阶B树(a B-tree of order m )是具有以下性质:
  • 每个点最多有m个孩子
  • 每个非叶子节点(根节点除外)最多有m/2(向上取整)个孩子
  • root至少有2个子树,除非root的孩子是叶子节点
  • k个孩子的非叶子节点含有k-1个键值
  • 所有的叶子节点都在同一层,并且内部节点不携带任何信息。(B树的阶指最大子节点数。优势,m阶的b树节点定义为有k个键值和k+1个指针,其中m<=k<=2m,用于指定最少的子节点数)

一些 提示:根结点为叶子结点,整棵树只有一个根节点
According to Knuth's definition, a B-tree of order m is a tree which satisfies the following properties:(wikipedia-BTree)

Every nod.e has at most m children.
Every non-leaf node (except root) has at least [m/2] children
The root has at least two children if it is not a leaf node.
A non-leaf node with k children contains k-1 keys.
All leaves appear in the same level, and internal vertices carry no information.





1.4.1.3 一些考点
1.4.1.3.1 B树与红黑树

不同:B树可以有很多的node(一般50-500),从而一个节点可以放下辅助存储器上一页或一整块的信息。
相同:一棵含有n节点的B树和红黑树的高度均为O(lgn).一般的,B树由于有多节点高度还是比红黑树要低一些。

1.4.1.4 实现
根据性质,B数往往至少是半满的,有较少的层,而且是完全平衡的。
下面通过类来实现,该类包含:
一个有m-1个单元的数组:存储键值
一个有m个单元的数组:存储指向其他节点的指针
可能包含其他信心来方便对树维护(friend)


template
       
        
class BTreeNode{
public:
  BTreeNode();
  BTreeNode(const T&);
private:
  bool leaf;
  int keyTally;
  T keys[M-1];
  BTreeNode *pointers[M];
  friend BTree
        
         ;
}

        
       

1.4.1.4.1 B树查找:

Searching in a B-tree

  • Start at root.
  • Find interval for search key and take corresponding link.
  • Search terminates in external node.


BTreeNode *BTreeSearch(keyType K,BTreeNode *node){
  if(node != 0){
    for(i=1;i
        
         keyTally && node->keys[i-1]
         
          node->node->keyTally||node->keys[i-1]>K)
      return BTreeSearch(K,node->pointers[i-1]);
    else
      return node;
  }
  else 
    return 0;
}

         
        




搜索最坏情况:when B树中每个非根节点只有最少的允许指针数目。 q=M/2(向下取整),而且搜索要一直到叶子节点(无论命中与否)

1.4.1.4.2  B树的插入

Insertion in a B-tree

  • Search for new key.
  • Insert at bottom.
  • Split nodes with M key-link pairs on the way up the tree.

B树特点:所有叶子节点在B树的最后一层,所以插入和删除并不简单。
===》》树自底向上建立。》》根节点处于不断变化中(until 所有插入完全后才能确定)
3种插入情况

  • 键值放入上有的空节点:叶节点内排序
  • 要超如键值叶节点已经满:分解叶节点,创建一个心的叶节点,将已满的叶节点中的一半键值移到新的叶节点中,并将新叶节点合并到B树中。
  • B树根节点是满的(2成立,一直到父节点全满的情况):创建一个心的根节点和一个与原根同级的新节点。(高度增加)





伪代码
BTreeInsert(K)
	找到一个叶节点node来插入k
	while(true)
		在数组keys中为k找到一个合适的位置;
		if node 不满
			插入K并递增keyTally;
			return;
		else			
			将node分解为node1(=node)与node2(新节点);
			在node1和node2之间平均分配键值和指针,并正确地初始化他们的keyTally;
		k=中间键值
		if node 是根节点
			穿件一个心的根节点,作为node1和node2的父节点
			将K及指针node1和node2的指针妨碍根节点中,并将根节点的keyTally设为1;
			return;
		else
			node = 其父节点。//处理父节点
		
1.4.1.4.3 B树的删除
删除操作在很大程度上是插入操作的逆过程。但,删除有更多的特殊情形。应该注意避免在删除后节点出现不到半满的情形。这意味着有时节点要合并。
2中情况:
  • 从叶节点删除:
    • 如果删除键值K后,叶节点至少是半满的,只有大于K的键值向左移动,来填补空位。(第一种情况的你操作)
    • 如果删除键值K后,叶节点中的键值个数少于【m/2】(向下取整)-1,则引起下溢
      • 如果左或右同级节点的键值数目超过下限,于是该叶节点和同级叶节点中的所有键值将在这两个叶节点中重新分配,在重新分配过程中,将父节点中划分这两个叶节点的键值移到这两个叶节点中,并从中选择中间键值,移到父节点中。
      • 如果叶节点下溢,其同级节点中键值的数目等于【m/2】-1,就合并该叶节点和同级节点。将该叶节点、同级叶节点及父节点中划分这两个叶节点的所有键值一起放进该叶节点中,然后删除同级节点,如果出现空位,就移动父节点中的键值。如果父节点出现下溢,则会引发以西医额擦做,这时候吧父节点当做叶节点,直到根部。(第二步的逆操作)
      • 当父节点是只有一个键值的根节点时,会出现一个特殊的情形,即合并叶节点或非也节点和他的同级节点。在这种情形下,该节点和其同级节点的键值,以及根节点的唯一键值一起放在一个心节点中,变成新的根节点。并删除源节点和其同级节点。这是两个节点在一次操作中一同消失的惟一情形。同时,树的高度-1.(第三步的逆过程)
  • 从非也节点中删除;(采用二叉搜索树中使用过的deleteByCopying())
    • 这或许会引起树结构的重组。因此从非叶子节点删除键值可以简化为从叶节点中删除键值。被删除的键值用其前驱取代(或后继)。这个后继键值从该叶节点中删除,回到第一种情形。

BTreeDelete(K)
	node = BTreeSearch(K,root)
	if(node!=null)
		if node 不是叶节点
			寻找一个带有最接近K的后继S的叶节点;
			把S赋值到K所在的node中;
			node = 包含S的叶节点;
			从node中删除S;
		else 从node 中删除K
		while(1)
			if node没有下溢
				return;
			else if node 有同级节点,且同级节点有足够多的键值
				在node和同级节点之间重新分配键值;
				return;
			else if node的父节点是根节点
				if 父节点只有一个键值
					合并node、它的同级节点以及父节点,形成一个心的根节点;
				else
					合并node和它的同级节点;
					return;
				else 合并node和它的同级节点;
					node = 它的父节点;
		

1.4.1.4.2 B树的平衡
Balance in B-tree

  • Proposition. A search or an insertion in a B-tree of order M with N keys requires between log_M-1(N) and log_M/2(N) probes.
  • Pf. All internal nodes (besides root) have between M / 2 and M - 1 links.
  • In practice. Number of probes is at most 4.(M = 1024; N = 62 billion log_M/2(N) ≤ 4)
  • Optimization. Always keep root page in memory.
Java 版本(4 Edition)
API for a B-tree page(JAVA)
                                                                             public class P age<Key>
Page(boolean bottom) 
                                                                             create and open a page
void close() 
                                                                             close a page
void add(Key key) 
                                                                             put key into the (external) page
void add(Page p)
                                                                             open p and put an entry into this (internal) page that 
                                                                             associates thesmallest key in p with p
boolean isExternal() 
                                                                             is this page external?
boolean contains(Key key) 
                                                                             is key in the page?
Page next(Key key) 
                                                                             the subtree that could contain the key
boolean isFull()
                                                                             has the page overflowed?
Page split() 
                                                                             move the highest-ranking half of the keys in the page to a 
                                                                             new page
Iterable<Key> keys()
                                                                             iterator for the keys on the page
/*************************************************************************
 *  Compilation:  javac BTree.java
 *  Execution:    java BTree
 *
 *  B-tree.
 *
 *  Limitations
 *  -----------
 *   -  Assumes M is even and M >= 4
 *   -  should b be an array of children or list (it would help with
 *      casting to make it a list)
 *
 *************************************************************************/


public class BTree
       
        , Value>  {
    private static final int M = 4;    // max children per B-tree node = M-1

    private Node root;             // root of the B-tree
    private int HT;                // height of the B-tree
    private int N;                 // number of key-value pairs in the B-tree

    // helper B-tree node data type
    private static final class Node {
        private int m;                             // number of children
        private Entry[] children = new Entry[M];   // the array of children
        private Node(int k) { m = k; }             // create a node with k children
    }

    // internal nodes: only use key and next
    // external nodes: only use key and value
    private static class Entry {
        private Comparable key;
        private Object value;
        private Node next;     // helper field to iterate over array entries
        public Entry(Comparable key, Object value, Node next) {
            this.key   = key;
            this.value = value;
            this.next  = next;
        }
    }

    // constructor
    public BTree() { root = new Node(0); }
 
    // return number of key-value pairs in the B-tree
    public int size() { return N; }

    // return height of B-tree
    public int height() { return HT; }


    // search for given key, return associated value; return null if no such key
    public Value get(Key key) { return search(root, key, HT); }
    private Value search(Node x, Key key, int ht) {
        Entry[] children = x.children;

        // external node
        if (ht == 0) {
            for (int j = 0; j < x.m; j++) {
                if (eq(key, children[j].key)) return (Value) children[j].value;
            }
        }

        // internal node
        else {
            for (int j = 0; j < x.m; j++) {
                if (j+1 == x.m || less(key, children[j+1].key))
                    return search(children[j].next, key, ht-1);
            }
        }
        return null;
    }


    // insert key-value pair
    // add code to check for duplicate keys
    public void put(Key key, Value value) {
        Node u = insert(root, key, value, HT); 
        N++;
        if (u == null) return;

        // need to split root
        Node t = new Node(2);
        t.children[0] = new Entry(root.children[0].key, null, root);
        t.children[1] = new Entry(u.children[0].key, null, u);
        root = t;
        HT++;
    }


    private Node insert(Node h, Key key, Value value, int ht) {
        int j;
        Entry t = new Entry(key, value, null);

        // external node
        if (ht == 0) {
            for (j = 0; j < h.m; j++) {
                if (less(key, h.children[j].key)) break;
            }
        }

        // internal node
        else {
            for (j = 0; j < h.m; j++) {
                if ((j+1 == h.m) || less(key, h.children[j+1].key)) {
                    Node u = insert(h.children[j++].next, key, value, ht-1);
                    if (u == null) return null;
                    t.key = u.children[0].key;
                    t.next = u;
                    break;
                }
            }
        }

        for (int i = h.m; i > j; i--) h.children[i] = h.children[i-1];
        h.children[j] = t;
        h.m++;
        if (h.m < M) return null;
        else         return split(h);
    }

    // split node in half
    private Node split(Node h) {
        Node t = new Node(M/2);
        h.m = M/2;
        for (int j = 0; j < M/2; j++)
            t.children[j] = h.children[M/2+j]; 
        return t;    
    }

    // for debugging
    public String toString() {
        return toString(root, HT, "") + "\n";
    }
    private String toString(Node h, int ht, String indent) {
        String s = "";
        Entry[] children = h.children;

        if (ht == 0) {
            for (int j = 0; j < h.m; j++) {
                s += indent + children[j].key + " " + children[j].value + "\n";
            }
        }
        else {
            for (int j = 0; j < h.m; j++) {
                if (j > 0) s += indent + "(" + children[j].key + ")\n";
                s += toString(children[j].next, ht-1, indent + "     ");
            }
        }
        return s;
    }


    // comparison functions - make Comparable instead of Key to avoid casts
    private boolean less(Comparable k1, Comparable k2) {
        return k1.compareTo(k2) < 0;
    }

    private boolean eq(Comparable k1, Comparable k2) {
        return k1.compareTo(k2) == 0;
    }


   /*************************************************************************
    *  test client
    *************************************************************************/
    public static void main(String[] args) {
        BTree
        
          st = new BTree
         
          ();

//      st.put("www.cs.princeton.edu", "128.112.136.12");
        st.put("www.cs.princeton.edu", "128.112.136.11");
        st.put("www.princeton.edu",    "128.112.128.15");
        st.put("www.yale.edu",         "130.132.143.21");
        st.put("www.simpsons.com",     "209.052.165.60");
        st.put("www.apple.com",        "17.112.152.32");
        st.put("www.amazon.com",       "207.171.182.16");
        st.put("www.ebay.com",         "66.135.192.87");
        st.put("www.cnn.com",          "64.236.16.20");
        st.put("www.google.com",       "216.239.41.99");
        st.put("www.nytimes.com",      "199.239.136.200");
        st.put("www.microsoft.com",    "207.126.99.140");
        st.put("www.dell.com",         "143.166.224.230");
        st.put("www.slashdot.org",     "66.35.250.151");
        st.put("www.espn.com",         "199.181.135.201");
        st.put("www.weather.com",      "63.111.66.11");
        st.put("www.yahoo.com",        "216.109.118.65");


        StdOut.println("cs.princeton.edu:  " + st.get("www.cs.princeton.edu"));
        StdOut.println("hardvardsucks.com: " + st.get("www.harvardsucks.com"));
        StdOut.println("simpsons.com:      " + st.get("www.simpsons.com"));
        StdOut.println("apple.com:         " + st.get("www.apple.com"));
        StdOut.println("ebay.com:          " + st.get("www.ebay.com"));
        StdOut.println("dell.com:          " + st.get("www.dell.com"));
        StdOut.println();

        StdOut.println("size:    " + st.size());
        StdOut.println("height:  " + st.height());
        StdOut.println(st);
        StdOut.println();
    }

}

         
        
       

1.4.1.5 评价
根据B树的定义,B树应该保证至少半满。所以,基本上会浪费50%的空间。当这种品庐出现过高时候,就应该对G树定义加以限制。
模拟和分析表明,在执行大量的随机插入和删除操作后,B树大约69%满。


Reference:
Bayer, R.; McCreight, E. (1972), "Organization and Maintenance of Large Ordered Indexes", Acta Informatica 1 (3): 173–189






error: refs/remotes/caf/A14-ES10-dev_34AA_release_ver0.800:无效的 sha1 指针 8e3f386776f8873a8fbc31cc7a8d29528499d403 error: refs/remotes/caf/A14-ES10-dev_34AA_release_ver0.810:无效的 sha1 指针 ebe262996c6e60159017a86cc116f3469b1b271f error: refs/remotes/caf/A14-ES10-dev_34AA_release_ver0.810_ECNR:无效的 sha1 指针 ebe262996c6e60159017a86cc116f3469b1b271f error: HEAD:无效的引用日志条目 5c9c6d9c976aaad453731994cfdd2833aa2fddfc error: HEAD:无效的引用日志条目 47e6c80e83fbcc6f5c2cc362f6dc580d0cfd4705 error: HEAD:无效的引用日志条目 47e6c80e83fbcc6f5c2cc362f6dc580d0cfd4705 error: HEAD:无效的引用日志条目 47e6c80e83fbcc6f5c2cc362f6dc580d0cfd4705 error: HEAD:无效的引用日志条目 47e6c80e83fbcc6f5c2cc362f6dc580d0cfd4705 error: HEAD:无效的引用日志条目 1e996cbd47d3a18b705ba4e45e7c55c3958b7906 error: HEAD:无效的引用日志条目 1e996cbd47d3a18b705ba4e45e7c55c3958b7906 error: HEAD:无效的引用日志条目 1e996cbd47d3a18b705ba4e45e7c55c3958b7906 error: HEAD:无效的引用日志条目 1e996cbd47d3a18b705ba4e45e7c55c3958b7906 error: HEAD:无效的引用日志条目 1e996cbd47d3a18b705ba4e45e7c55c3958b7906 error: HEAD:无效的引用日志条目 0dfd264a2b8f0e25dcf71f4eb093b97e6285c010 error: HEAD:无效的引用日志条目 9e7f556af7d619e27532c53fb624a5fb86ecd9d6 error: HEAD:无效的引用日志条目 9e7f556af7d619e27532c53fb624a5fb86ecd9d6 error: HEAD:无效的引用日志条目 9e7f556af7d619e27532c53fb624a5fb86ecd9d6 error: HEAD:无效的引用日志条目 9e7f556af7d619e27532c53fb624a5fb86ecd9d6 error: HEAD:无效的引用日志条目 58c484c4e1b6b3fd5a6e90e23752664855fdfee8 error: HEAD:无效的引用日志条目 58c484c4e1b6b3fd5a6e90e23752664855fdfee8 error: HEAD:无效的引用日志条目 58c484c4e1b6b3fd5a6e90e23752664855fdfee8 error: HEAD:无效的引用日志条目 58c484c4e1b6b3fd5a6e90e23752664855fdfee8 error: HEAD:无效的引用日志条目 f251caf2fa3af19c01e9f9c0122ed0e3c1f7e2fc error: HEAD:无效的引用日志条目 f251caf2fa3af19c01e9f9c0122ed0e3c1f7e2fc error: HEAD:无效的引用日志条目 cf453954c561bc7287fd08b957857900bb87ebc4 error: HEAD:无效的引用日志条目 cf453954c561bc7287fd08b957857900bb87ebc4 error: HEAD:无效的引用日志条目 d615657b427937bee4b176f409ee286d69d6310e error: HEAD:无效的引用日志条目 d615657b427937bee4b176f409ee286d69d6310e error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 0dfd264a2b8f0e25dcf71f4eb093b97e6285c010 error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 9e7f556af7d619e27532c53fb624a5fb86ecd9d6 error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 58c484c4e1b6b3fd5a6e90e23752664855fdfee8 error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 58c484c4e1b6b3fd5a6e90e23752664855fdfee8 error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 f251caf2fa3af19c01e9f9c0122ed0e3c1f7e2fc error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 f251caf2fa3af19c01e9f9c0122ed0e3c1f7e2fc error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 cf453954c561bc7287fd08b957857900bb87ebc4 error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 cf453954c561bc7287fd08b957857900bb87ebc4 error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 d615657b427937bee4b176f409ee286d69d6310e error: refs/remotes/caf/A14-ES10-dev:无效的引用日志条目 d615657b427937bee4b176f409ee286d69d6310e error: refs/heads/A14-ES10-dev:无效的引用日志条目 0dfd264a2b8f0e25dcf71f4eb093b97e6285c010 error: refs/heads/A14-ES10-dev:无效的引用日志条目 9e7f556af7d619e27532c53fb624a5fb86ecd9d6 error: refs/heads/A14-ES10-dev:无效的引用日志条目 58c484c4e1b6b3fd5a6e90e23752664855fdfee8 error: refs/heads/A14-ES10-dev:无效的引用日志条目 58c484c4e1b6b3fd5a6e90e23752664855fdfee8 error: refs/heads/A14-ES10-dev:无效的引用日志条目 f251caf2fa3af19c01e9f9c0122ed0e3c1f7e2fc error: refs/heads/A14-ES10-dev:无效的引用日志条目 f251caf2fa3af19c01e9f9c0122ed0e3c1f7e2fc error: refs/heads/A14-ES10-dev:无效的引用日志条目 cf453954c561bc7287fd08b957857900bb87ebc4 error: refs/heads/A14-ES10-dev:无效的引用日志条目 cf453954c561bc7287fd08b957857900bb87ebc4 error: refs/heads/A14-ES10-dev:无效的引用日志条目 d615657b427937bee4b176f409ee286d69d6310e error: refs/heads/A14-ES10-dev:无效的引用日志条目 d615657b427937bee4b176f409ee286d69d6310e error: 17cc526564e517733f5125d975f02e86dc9c1f45:cache-tree 中无效的 sha1 指针 error: ae519f40b39d99da5a00d9e999d931240438a804:cache-tree 中无效的 sha1 指针 error: 00b9b1fc89579c91677ae881c071613d35cee8fd:cache-tree 中无效的 sha1 指针 error: 54c710f232a56c5c13e059504e507e55fee39e75:cache-tree 中无效的 sha1 指针 error: 5eff05e9a8c4df3730fd27811e8086dc4d30e7ef:cache-tree 中无效的 sha1 指针 error: 624556b23d69c74a390a614c8f125b57e4a1c1c2:cache-tree 中无效的 sha1 指针 error: a170efbf95964f448f9afa0ee0a2f3152568dcfd:cache-tree 中无效的 sha1 指针 error: 34c21469e0a1000878727ae9bb1a24ff7fb2cb5e:cache-tree 中无效的 sha1 指针 损坏的链接来自于 tree 034dca331c556c733c1b41133673b827b8305aad 到 tree 5eff05e9a8c4df3730fd27811e8086dc4d30e7ef 损坏的链接来自于 tree 034dca331c556c733c1b41133673b827b8305aad 到 tree 624556b23d69c74a390a614c8f125b57e4a1c1c2 损坏的链接来自于 tree e110a4c8eeb4c845b63979e4ee0a812e2583d5f3 到 tree a170efbf95964f448f9afa0ee0a2f3152568dcfd 损坏的链接来自于 tree 8b13a2eebadb62ea2c640d476f1f313c74652f9c 到 tree 54c710f232a56c5c13e059504e507e55fee39e75 损坏的链接来自于 tree 8b13a2eebadb62ea2c640d476f1f313c74652f9c 到 tree ae519f40b39d99da5a00d9e999d931240438a804 损坏的链接来自于 tree 8b13a2eebadb62ea2c640d476f1f313c74652f9c 到 tree 17cc526564e517733f5125d975f02e86dc9c1f45 损坏的链接来自于 tree 8b13a2eebadb62ea2c640d476f1f313c74652f9c 到 tree 00b9b1fc89579c91677ae881c071613d35cee8fd 损坏的链接来自于 tree 3c3b662d58dc282be2b7efde36cfe414f934336d 到 tree 34c21469e0a1000878727ae9bb1a24ff7fb2cb5e 损坏的链接来自于 tree 4c36acf032aa02c90e79b79544feac8c497a4cca 到 blob 64af01e4c0738f7aabce8d9350b992a50bad3a77 损坏的链接来自于 tree e833008ec25e74316c7388f09bbef081aba64004 到 tree 98612a6fe99a77188bbcdcf3bc5d77107d56edd2 损坏的链接来自于 tree 49f5df75101542966651614ca044e9a7ad0f67a9 到 blob 890081cc7f3b216d3424af475939bbe8bbedffb9 损坏的链接来自于 tree 49f5df75101542966651614ca044e9a7ad0f67a9 到 blob 438f10cc0b6be63a7f9fc0ef7be0f3c4ee2a4230 损坏的链接来自于 tree 711367b24b6eea7dc7ec00ea8540777aafdf327c 到 blob 818eafcef49dc09cc9d03ddbbe8f0743d8fc8acc 损坏的链接来自于 tree 58cf2d382ed3ad9f722d4996f057825c913930f7 到 blob 28fe6a2a36153bb5c73c3620cc778e954a3a01e5 损坏的链接来自于 tree 58cf2d382ed3ad9f722d4996f057825c913930f7 到 blob 58ce89b0f74f51e0768e80f059670d847c03e526 损坏的链接来自于 tree dfcc2d0fd591754bfc3b7d701bd63901f37d3f39 到 blob f86ca36b18cee7dd7063162a511e7a221e38f7f9 损坏的链接来自于 tree 5087e0b8c8c160b49705e0499365a7b7b6d38611 到 blob 6f8a190240fd6a8e8ff5f2a858402e7d871123c8 损坏的链接来自于 tree 5087e0b8c8c160b49705e0499365a7b7b6d38611 到 blob 84e360877a0fde92fc5ad1cdc65cc886b8e50177 损坏的链接来自于 tree c152d7138184c0eac62cd2845f25a13bc8af43d1 到 blob ca13e39922740dc627ff7485525b270f4dd0833a 损坏的链接来自于 tree c152d7138184c0eac62cd2845f25a13bc8af43d1 到 blob 19c713c411d682e92a0a93522cf32ccf82dcb563 损坏的链接来自于 tree fde320bcce409e04da79dde51234b7c008263130 到 blob 5328a193f0eee04af6c7ede0e9a15678735c6c62 损坏的链接来自于 tree fde320bcce409e04da79dde51234b7c008263130 到 blob 6df34b37547fd5cbcab3a0c012bca4d7387187ed 损坏的链接来自于 tree fde320bcce409e04da79dde51234b7c008263130 到 tree 2ec5d3dcade54c7637d3eb12657f5405f5b319b0 损坏的链接来自于 tree 3f89bd0991b6d8ca3acad6be3feae516ac097213 到 tree 3137a1a53d9b9d09147702899e746bd9802d35ad 损坏的链接来自于 tree 423f93f4ada793d363fed2b8affef76aeefac4c9 到 blob 10270862f5524a1ac3da4f44505edd5f2cb890b6 损坏的链接来自于 tree 423f93f4ada793d363fed2b8affef76aeefac4c9 到 tree 91156109a72372598e3437f73167d43b1e251329 损坏的链接来自于 tree 423f93f4ada793d363fed2b8affef76aeefac4c9 到 tree cbce8c52f204d67114572e276e98c859599dc8bb 损坏的链接来自于 tree 423f93f4ada793d363fed2b8affef76aeefac4c9 到 tree 85fc88955be0ee372611a8a572b7be446f3abab4 损坏的链接来自于 tree 423f93f4ada793d363fed2b8affef76aeefac4c9 到 tree 262d7005db81b6ec5630d89ccd256da332c612f7 损坏的链接来自于 tree 423f93f4ada793d363fed2b8affef76aeefac4c9 到 tree 07acb6b0b1efc9f853cfe070d303ac76d5c038ad 损坏的链接来自于 tree bf0e95167991cbae9554adeb37c182f94b531185 到 blob a04942b83838e954ffc25f930fc210fde4506ca1 损坏的链接来自于 tree bf0e95167991cbae9554adeb37c182f94b531185 到 blob dc8dbe9bd1a750f5d24432be1ac7d8a624d52dab 损坏的链接来自于 tree bf0e95167991cbae9554adeb37c182f94b531185 到 blob 5090d93fab444a7853537df0b3f04dbaa01ffa5d 损坏的链接来自于 tree 3bdbdc4e42f1635f0d21e17590d7d31d17a79b6f 到 blob 92d0f4d6ad02ddf7b241525467719ba91bc40ce3 损坏的链接来自于 tree 3bdbdc4e42f1635f0d21e17590d7d31d17a79b6f 到 blob 08f67aeb8b80979b61b6240ad912e9575e0e60c2 损坏的链接来自于 tree 3bdbdc4e42f1635f0d21e17590d7d31d17a79b6f 到 blob 32303e11430d6ce1358d39107526914cb54b23b1 损坏的链接来自于 tree 3bdbdc4e42f1635f0d21e17590d7d31d17a79b6f 到 blob aaaf7a02e40a63f3493af9921f87760cee7ad1b0 损坏的链接来自于 tree 3bdbdc4e42f1635f0d21e17590d7d31d17a79b6f 到 blob 9cce3346e36196dc1ed0c8f26b1607fa99cf8bb7 损坏的链接来自于 tree 2d3e726715f9609d09ea481046eda4ed9ba76b4c 到 blob 5273ef2517ecfb1a580fd73911f2e2fdc27156f9 损坏的链接来自于 tree 2d3e726715f9609d09ea481046eda4ed9ba76b4c 到 blob e1396c94a26ecc80ce73400552ad196495c43ff6 损坏的链接来自于 tree 2d3e726715f9609d09ea481046eda4ed9ba76b4c 到 blob ddd2814ef5ce84b85d49826554a601cf1ef7cac8 损坏的链接来自于 tree 2d3e726715f9609d09ea481046eda4ed9ba76b4c 到 tree f44731688deefa5dd00c458537fba385641d0716 损坏的链接来自于 tree 70db46b1dd9767a56c6cb1196f6a9a56a06b1a6d 到 tree 30a131ced84c4a3bc18fc7a439605e6b33d522da 损坏的链接来自于 tree 70db46b1dd9767a56c6cb1196f6a9a56a06b1a6d 到 tree 651bc4f8f285821fc6e8f5182b94b9412ec7c419 损坏的链接来自于 tree 70db46b1dd9767a56c6cb1196f6a9a56a06b1a6d 到 tree 5c1aa39bf4e67eaed6f315f2db6f30d190632a65 损坏的链接来自于 tree 1506f5cd936e3ef8301d633e77a55448ac1f8b2a 到 blob bf9f90594de117e0cdb72146a6d1eba2ae6ee838 损坏的链接来自于 tree 89da51de19d100537cf5f1d1ca324edbeda02fd0 到 blob 048372bae66ce322ca4c38bbfd7d12c505da1eb9 损坏的链接来自于 tree 89da51de19d100537cf5f1d1ca324edbeda02fd0 到 blob cc220d087ec6ffb9c8ba561dd11243dffb10848d 损坏的链接来自于 tree 89da51de19d100537cf5f1d1ca324edbeda02fd0 到 blob 20e32802d91ab5b330189474fa3441aca7de4695 损坏的链接来自于 tree 89da51de19d100537cf5f1d1ca324edbeda02fd0
07-18
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值