概要

前面分别介绍了红黑树的理论知识 以及 通过C语言实现了红黑树。本章继续会红黑树进行介绍,下面将Linux 内核中的红黑树单独移植出来进行测试验证。若读者对红黑树的理论知识不熟悉,建立先学习红黑树的理论知识,再来学习本章。

转载请注明出处:http://www.cnblogs.com/skywang12345/p/3624202.html


更多内容:数据结构与算法系列 目录

(01) 红黑树(一)之 原理和算法详细介绍
(02) 红黑树(二)之 C语言的实现
(03) 红黑树(三)之 Linux内核中红黑树的经典实现(04) 红黑树(四)之 C++的实现(05) 红黑树(五)之 Java的实现(06) 红黑树(六)之 参考资料

Linux内核中红黑树(完整源码)

红黑树的实现文件(rbtree.h)

 /*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de> This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA linux/include/linux/rbtree.h To use rbtrees you'll have to implement your own insert and search cores.
This will avoid us to use callbacks and to drop drammatically performances.
I know it's not the cleaner way, but in C (not in C++) to get
performances and genericity... Some example of insert and search follows here. The search is a plain
normal search over an ordered tree. The insert instead must be implemented
in two steps: First, the code must insert the element in order as a red leaf
in the tree, and then the support library function rb_insert_color() must
be called. Such function will do the not trivial work to rebalance the
rbtree, if necessary. -----------------------------------------------------------------------
static inline struct page * rb_search_page_cache(struct inode * inode,
unsigned long offset)
{
struct rb_node * n = inode->i_rb_page_cache.rb_node;
struct page * page; while (n)
{
page = rb_entry(n, struct page, rb_page_cache); if (offset < page->offset)
n = n->rb_left;
else if (offset > page->offset)
n = n->rb_right;
else
return page;
}
return NULL;
} static inline struct page * __rb_insert_page_cache(struct inode * inode,
unsigned long offset,
struct rb_node * node)
{
struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
struct rb_node * parent = NULL;
struct page * page; while (*p)
{
parent = *p;
page = rb_entry(parent, struct page, rb_page_cache); if (offset < page->offset)
p = &(*p)->rb_left;
else if (offset > page->offset)
p = &(*p)->rb_right;
else
return page;
} rb_link_node(node, parent, p); return NULL;
} static inline struct page * rb_insert_page_cache(struct inode * inode,
unsigned long offset,
struct rb_node * node)
{
struct page * ret;
if ((ret = __rb_insert_page_cache(inode, offset, node)))
goto out;
rb_insert_color(node, &inode->i_rb_page_cache);
out:
return ret;
}
-----------------------------------------------------------------------
*/ #ifndef _SLINUX_RBTREE_H
#define _SLINUX_RBTREE_H #include <stdio.h>
//#include <linux/kernel.h>
//#include <linux/stddef.h> struct rb_node
{
unsigned long rb_parent_color;
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} /* __attribute__((aligned(sizeof(long))))*/;
/* The alignment might seem pointless, but allegedly CRIS needs it */ struct rb_root
{
struct rb_node *rb_node;
}; #define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
#define rb_color(r) ((r)->rb_parent_color & 1)
#define rb_is_red(r) (!rb_color(r))
#define rb_is_black(r) rb_color(r)
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->rb_parent_color = (rb->rb_parent_color & ) | (unsigned long)p;
}
static inline void rb_set_color(struct rb_node *rb, int color)
{
rb->rb_parent_color = (rb->rb_parent_color & ~) | color;
} #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ \
const typeof( ((type *))->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );}) #define RB_ROOT (struct rb_root) { NULL, }
#define rb_entry(ptr, type, member) container_of(ptr, type, member) #define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) static inline void rb_init_node(struct rb_node *rb)
{
rb->rb_parent_color = ;
rb->rb_right = NULL;
rb->rb_left = NULL;
RB_CLEAR_NODE(rb);
} extern void rb_insert_color(struct rb_node *, struct rb_root *);
extern void rb_erase(struct rb_node *, struct rb_root *); typedef void (*rb_augment_f)(struct rb_node *node, void *data); extern void rb_augment_insert(struct rb_node *node,
rb_augment_f func, void *data);
extern struct rb_node *rb_augment_erase_begin(struct rb_node *node);
extern void rb_augment_erase_end(struct rb_node *node,
rb_augment_f func, void *data); /* Find logical next and previous nodes in a tree */
extern struct rb_node *rb_next(const struct rb_node *);
extern struct rb_node *rb_prev(const struct rb_node *);
extern struct rb_node *rb_first(const struct rb_root *);
extern struct rb_node *rb_last(const struct rb_root *); /* Fast replacement of a single node without remove/rebalance/add/rebalance */
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root); static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
struct rb_node ** rb_link)
{
node->rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL; *rb_link = node;
} #endif /* _LINUX_RBTREE_H */

红黑树的实现文件(rbtree.c)

 /*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
(C) 2002 David Woodhouse <dwmw2@infradead.org> This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA linux/lib/rbtree.c
*/ #include "rbtree.h" static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
{
struct rb_node *right = node->rb_right;
struct rb_node *parent = rb_parent(node); if ((node->rb_right = right->rb_left))
rb_set_parent(right->rb_left, node);
right->rb_left = node; rb_set_parent(right, parent); if (parent)
{
if (node == parent->rb_left)
parent->rb_left = right;
else
parent->rb_right = right;
}
else
root->rb_node = right;
rb_set_parent(node, right);
} static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
{
struct rb_node *left = node->rb_left;
struct rb_node *parent = rb_parent(node); if ((node->rb_left = left->rb_right))
rb_set_parent(left->rb_right, node);
left->rb_right = node; rb_set_parent(left, parent); if (parent)
{
if (node == parent->rb_right)
parent->rb_right = left;
else
parent->rb_left = left;
}
else
root->rb_node = left;
rb_set_parent(node, left);
} void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent; while ((parent = rb_parent(node)) && rb_is_red(parent))
{
gparent = rb_parent(parent); if (parent == gparent->rb_left)
{
{
register struct rb_node *uncle = gparent->rb_right;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
} if (parent->rb_right == node)
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
} rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_right(gparent, root);
} else {
{
register struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
} if (parent->rb_left == node)
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
} rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_left(gparent, root);
}
} rb_set_black(root->rb_node);
} static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
struct rb_root *root)
{
struct rb_node *other; while ((!node || rb_is_black(node)) && node != root->rb_node)
{
if (parent->rb_left == node)
{
other = parent->rb_right;
if (rb_is_red(other))
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_left(parent, root);
other = parent->rb_right;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right)))
{
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->rb_right || rb_is_black(other->rb_right))
{
rb_set_black(other->rb_left);
rb_set_red(other);
__rb_rotate_right(other, root);
other = parent->rb_right;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->rb_right);
__rb_rotate_left(parent, root);
node = root->rb_node;
break;
}
}
else
{
other = parent->rb_left;
if (rb_is_red(other))
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_right(parent, root);
other = parent->rb_left;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right)))
{
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->rb_left || rb_is_black(other->rb_left))
{
rb_set_black(other->rb_right);
rb_set_red(other);
__rb_rotate_left(other, root);
other = parent->rb_left;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
rb_set_black(other->rb_left);
__rb_rotate_right(parent, root);
node = root->rb_node;
break;
}
}
}
if (node)
rb_set_black(node);
} void rb_erase(struct rb_node *node, struct rb_root *root)
{
struct rb_node *child, *parent;
int color; if (!node->rb_left)
child = node->rb_right;
else if (!node->rb_right)
child = node->rb_left;
else
{
struct rb_node *old = node, *left; node = node->rb_right;
while ((left = node->rb_left) != NULL)
node = left; if (rb_parent(old)) {
if (rb_parent(old)->rb_left == old)
rb_parent(old)->rb_left = node;
else
rb_parent(old)->rb_right = node;
} else
root->rb_node = node; child = node->rb_right;
parent = rb_parent(node);
color = rb_color(node); if (parent == old) {
parent = node;
} else {
if (child)
rb_set_parent(child, parent);
parent->rb_left = child; node->rb_right = old->rb_right;
rb_set_parent(old->rb_right, node);
} node->rb_parent_color = old->rb_parent_color;
node->rb_left = old->rb_left;
rb_set_parent(old->rb_left, node); goto color;
} parent = rb_parent(node);
color = rb_color(node); if (child)
rb_set_parent(child, parent);
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child; color:
if (color == RB_BLACK)
__rb_erase_color(child, parent, root);
} static void rb_augment_path(struct rb_node *node, rb_augment_f func, void *data)
{
struct rb_node *parent; up:
func(node, data);
parent = rb_parent(node);
if (!parent)
return; if (node == parent->rb_left && parent->rb_right)
func(parent->rb_right, data);
else if (parent->rb_left)
func(parent->rb_left, data); node = parent;
goto up;
} /*
* after inserting @node into the tree, update the tree to account for
* both the new entry and any damage done by rebalance
*/
void rb_augment_insert(struct rb_node *node, rb_augment_f func, void *data)
{
if (node->rb_left)
node = node->rb_left;
else if (node->rb_right)
node = node->rb_right; rb_augment_path(node, func, data);
} /*
* before removing the node, find the deepest node on the rebalance path
* that will still be there after @node gets removed
*/
struct rb_node *rb_augment_erase_begin(struct rb_node *node)
{
struct rb_node *deepest; if (!node->rb_right && !node->rb_left)
deepest = rb_parent(node);
else if (!node->rb_right)
deepest = node->rb_left;
else if (!node->rb_left)
deepest = node->rb_right;
else {
deepest = rb_next(node);
if (deepest->rb_right)
deepest = deepest->rb_right;
else if (rb_parent(deepest) != node)
deepest = rb_parent(deepest);
} return deepest;
} /*
* after removal, update the tree to account for the removed entry
* and any rebalance damage.
*/
void rb_augment_erase_end(struct rb_node *node, rb_augment_f func, void *data)
{
if (node)
rb_augment_path(node, func, data);
} /*
* This function returns the first node (in sort order) of the tree.
*/
struct rb_node *rb_first(const struct rb_root *root)
{
struct rb_node *n; n = root->rb_node;
if (!n)
return NULL;
while (n->rb_left)
n = n->rb_left;
return n;
} struct rb_node *rb_last(const struct rb_root *root)
{
struct rb_node *n; n = root->rb_node;
if (!n)
return NULL;
while (n->rb_right)
n = n->rb_right;
return n;
} struct rb_node *rb_next(const struct rb_node *node)
{
struct rb_node *parent; if (rb_parent(node) == node)
return NULL; /* If we have a right-hand child, go down and then left as far
as we can. */
if (node->rb_right) {
node = node->rb_right;
while (node->rb_left)
node=node->rb_left;
return (struct rb_node *)node;
} /* No right-hand children. Everything down and left is
smaller than us, so any 'next' node must be in the general
direction of our parent. Go up the tree; any time the
ancestor is a right-hand child of its parent, keep going
up. First time it's a left-hand child of its parent, said
parent is our 'next' node. */
while ((parent = rb_parent(node)) && node == parent->rb_right)
node = parent; return parent;
} struct rb_node *rb_prev(const struct rb_node *node)
{
struct rb_node *parent; if (rb_parent(node) == node)
return NULL; /* If we have a left-hand child, go down and then right as far
as we can. */
if (node->rb_left) {
node = node->rb_left;
while (node->rb_right)
node=node->rb_right;
return (struct rb_node *)node;
} /* No left-hand children. Go up till we find an ancestor which
is a right-hand child of its parent */
while ((parent = rb_parent(node)) && node == parent->rb_left)
node = parent; return parent;
} void rb_replace_node(struct rb_node *victim, struct rb_node *new,
struct rb_root *root)
{
struct rb_node *parent = rb_parent(victim); /* Set the surrounding nodes to point to the replacement */
if (parent) {
if (victim == parent->rb_left)
parent->rb_left = new;
else
parent->rb_right = new;
} else {
root->rb_node = new;
}
if (victim->rb_left)
rb_set_parent(victim->rb_left, new);
if (victim->rb_right)
rb_set_parent(victim->rb_right, new); /* Copy the pointers/colour from the victim to the replacement */
*new = *victim;
}

红黑树的测试文件(test.c)

 /**
* 根据Linux Kernel定义的红黑树(Red Black Tree)
*
* @author skywang
* @date 2013/11/18
*/ #include <stdio.h>
#include <stdlib.h>
#include "rbtree.h" #define CHECK_INSERT 0 // "插入"动作的检测开关(0,关闭;1,打开)
#define CHECK_DELETE 0 // "删除"动作的检测开关(0,关闭;1,打开)
#define LENGTH(a) ( (sizeof(a)) / (sizeof(a[0])) ) typedef int Type; struct my_node {
struct rb_node rb_node; // 红黑树节点
Type key; // 键值
// ... 用户自定义的数据
}; /*
* 查找"红黑树"中键值为key的节点。没找到的话,返回NULL。
*/
struct my_node *my_search(struct rb_root *root, Type key)
{
struct rb_node *rbnode = root->rb_node; while (rbnode!=NULL)
{
struct my_node *mynode = container_of(rbnode, struct my_node, rb_node); if (key < mynode->key)
rbnode = rbnode->rb_left;
else if (key > mynode->key)
rbnode = rbnode->rb_right;
else
return mynode;
} return NULL;
} /*
* 将key插入到红黑树中。插入成功,返回0;失败返回-1。
*/
int my_insert(struct rb_root *root, Type key)
{
struct my_node *mynode; // 新建结点
struct rb_node **tmp = &(root->rb_node), *parent = NULL; /* Figure out where to put new node */
while (*tmp)
{
struct my_node *my = container_of(*tmp, struct my_node, rb_node); parent = *tmp;
if (key < my->key)
tmp = &((*tmp)->rb_left);
else if (key > my->key)
tmp = &((*tmp)->rb_right);
else
return -;
} // 如果新建结点失败,则返回。
if ((mynode=malloc(sizeof(struct my_node))) == NULL)
return -;
mynode->key = key; /* Add new node and rebalance tree. */
rb_link_node(&mynode->rb_node, parent, tmp);
rb_insert_color(&mynode->rb_node, root); return ;
} /*
* 删除键值为key的结点
*/
void my_delete(struct rb_root *root, Type key)
{
struct my_node *mynode; // 在红黑树中查找key对应的节点mynode
if ((mynode = my_search(root, key)) == NULL)
return ; // 从红黑树中删除节点mynode
rb_erase(&mynode->rb_node, root);
free(mynode);
} /*
* 打印"红黑树"
*/
static void print_rbtree(struct rb_node *tree, Type key, int direction)
{
if(tree != NULL)
{
if(direction==) // tree是根节点
printf("%2d(B) is root\n", key);
else // tree是分支节点
printf("%2d(%s) is %2d's %6s child\n", key, rb_is_black(tree)?"B":"R", key, direction==?"right" : "left"); if (tree->rb_left)
print_rbtree(tree->rb_left, rb_entry(tree->rb_left, struct my_node, rb_node)->key, -);
if (tree->rb_right)
print_rbtree(tree->rb_right,rb_entry(tree->rb_right, struct my_node, rb_node)->key, );
}
} void my_print(struct rb_root *root)
{
if (root!=NULL && root->rb_node!=NULL)
print_rbtree(root->rb_node, rb_entry(root->rb_node, struct my_node, rb_node)->key, );
} void main()
{
int a[] = {, , , , , , , , };
int i, ilen=LENGTH(a);
struct rb_root mytree = RB_ROOT; printf("== 原始数据: ");
for(i=; i<ilen; i++)
printf("%d ", a[i]);
printf("\n"); for (i=; i < ilen; i++)
{
my_insert(&mytree, a[i]);
#if CHECK_INSERT
printf("== 添加节点: %d\n", a[i]);
printf("== 树的详细信息: \n");
my_print(&mytree);
printf("\n");
#endif } #if CHECK_DELETE
for (i=; i<ilen; i++) {
my_delete(&mytree, a[i]); printf("== 删除节点: %d\n", a[i]);
printf("== 树的详细信息: \n");
my_print(&mytree);
printf("\n");
}
#endif
}

rbtree.h和rbtree.c基本上是从Linux 3.0的Kernel中移植出来的。仅仅只添加了offestof和container_of两个宏,这两个宏在文章"Linux内核中双向链表的经典实现"中已经介绍过了,这里就不再重复说明了。
test.c中包含了两部分内容:一是,基于内核红黑树接口,自定义的一个结构体,并提供了相应的接口(添加、删除、搜索、打印)。二是,包含了相应的测试程序。

红黑树(三)之 Linux内核中红黑树的经典实现的更多相关文章

  1. 作业三:LINUX内核的启动过程

    作业三:LINUX内核的启动过程 一.使用GDB跟踪内核从start_kernel到init进程启动(附实验截图) (一)使用自己的Linux系统环境搭建MenuOS的过程 下载内核源代码编译内核 c ...

  2. Linux内核中双向链表的经典实现

    概要 前面一章"介绍双向链表并给出了C/C++/Java三种实现",本章继续对双向链表进行探讨,介绍的内容是Linux内核中双向链表的经典实现和用法.其中,也会涉及到Linux内核 ...

  3. Linux内核及分析 第三周 Linux内核的启动过程

    实验过程: 打开shell终端,执行以下命令: cd LinuxKernel/ qemu -kernel linux-3.18.6/arch/x86/boot/bzImage-initrd rootf ...

  4. 详解Linux内核红黑树算法的实现

    转自:https://blog.csdn.net/npy_lp/article/details/7420689 内核源码:linux-2.6.38.8.tar.bz2 关于二叉查找树的概念请参考博文& ...

  5. C高级 框架开发中红黑树结构

    引言  -- 红黑树历史 红黑树是数据结构学习中一道卡. 底层库容器中必不可少的算法. 历经各种实战运用,性能有保障. 同样红黑树不好理解, 就算理解了, 代码也不好写. 就算写了, 工程库也难构建. ...

  6. linux 内核数据结构之红黑树.

    转载: http://www.cnblogs.com/haippy/archive/2012/09/02/2668099.html https://zh.wikipedia.org/zh/%E7%BA ...

  7. 《Linux内核分析》课程第三周学习总结

    姓名:何伟钦 学号:20135223 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...

  8. linux内核分析 第三周 构造一个简单的Linux系统MenuOS

    一.计算机的三个法宝 存储程序计算机,函数调用堆栈,中断二.操作系统的两把剑:1.中断上下文的切换,保存现场和恢复现场2.进程上下文的切换. 三.linux内核源代码的分析: ·arch/目录保存支持 ...

  9. Linux内核分析(三)内核启动过程分析——构造一个简单的Linux系统

    一.系统的启动(各历史节点) 在最开始的时候,计算机的启动实际上依靠一段二进制码,可以这么理解,他并不是一个真正的计算机启动一道程序.计算机在开始加电的时候几乎是没有任何用处的,因为RAM芯片中包括的 ...

随机推荐

  1. sqlserver自定义函数的创建与调用

    sqlserver中有系统提供的函数,像avg.sum.getdate()等,用户还可以自定义函数. 用户自定义的函数包括:标量函数和表值函数,其中标量函数和系统函数的用法一样,表值函数根据主体的定义 ...

  2. 在线教程的游戏化-20分钟做了个demo

    首先,不准说做得撇,因为其一,我只用了20分钟不到:其二,第一次尝试,以前想过,但是一直没有搞过,二话不说,先来截图,下载地址在最下面. 因为第一次尝试,所以很多事件自己还没有闹明白,不过基本上还是看 ...

  3. Number Range 管理之并行缓冲

    Number Range 管理之并行缓冲: 常用的事务代码SNRO,SM56还有一些业务专用的号码管理,可以在SPRO中查找: SNRO :Number Range 管理 一般的操作是维护号码范围.如 ...

  4. DNS劫持

    忽然发现我最喜欢的chrome 一直有广告,好些论坛都有大量的广告,原以为是重了什么插件了,找了也没发现,有可能是DNS劫持. 打开路由器,找到 dns 设置里面把里面的全部去掉.然后把 192.16 ...

  5. mysql中You can’t specify target table for update in FROM clause错误解决方法

    mysql中You can't specify target table for update in FROM clause错误的意思是说,不能先select出同一表中的某些值,再update这个表( ...

  6. (转)c#.net常用字符串函数

    Compare 比较字符串的内容,考虑文化背景(场所),确定某些字符是否相等 CompareOrdinal 与Compare一样,但不考虑文化背景 Format 格式化包含各种值的字符串和如何格式化每 ...

  7. [算法导论]拓扑排序 @ Python

    class Graph: def __init__(self): self.V = [] class Vertex: def __init__(self, x): self.key = x self. ...

  8. mybatis 返回null 及 参数说明

    'org.mybatis:mybatis:3.2.8' (会与 'org.mybatis:mybatis:3.1.1',com.mybank.tools.dialect.PaginationInter ...

  9. 解决cxf+spring发布的webservice,types,portType和message以import方式导入

    用cxf+spring发布了webservice,发现生成的wsdl的types,message和portType都以import的方式导入的.. 原因:命名空间问题 我想要生成的wsdl在同个文件中 ...

  10. 查看android app 线程信息的命令

    参考:https://my.oschina.net/zhiweiofli/blog/138454 ps | grep 'joyodream' 找到 app 的pid: joyodream为包名的一部分 ...