平衡树学习笔记(6)-------RBT
RBT
RBT是。。。是一棵恐怖的树
有多恐怖?
平衡树中最快的♂
不到200ms的优势,连权值线段树都无法匹敌
但是,通过大量百度,发现RBT的代码都是从STL扒的qwq
蒟蒻根本无法研究透彻
关键时候,崔大钊(<-----数据结构巨佬)使用了终极武器花_Q帮助了我(雾
硬生生把左旋右旋压在一起,800多行-->100多行,使我更加透彻QAQ
感激不尽(▽)
不废话了qwq
RBT,中文名红黑树,即Red-Black-Tree
是个巨佬级别的数据结构
它为每个点规定了颜色(不是红就是黑)
下面说它的几个性质
\(\color{#3399ff}{1、每个节点有且只有两种颜色:黑||红}\)
\(\color{#3399ff}{2、根为黑色}\)
\(\color{#3399ff}{3、叶子节点为黑色。注:叶子节点是额外的空节点}\)
\(\color{#3399ff}{4、如果某节点是红色的,那么TA的左右儿子必须是黑色的}\)
\(\color{#3399ff}{5、从每个节点出发,到它子树内的叶子节点所经过的黑节点的个数相同,我们把这个黑节点的个数称为黑高度}\)
可以仔细思(tou)考(che)一下,不难发现,RBT保证平衡的方法
由于性质5,可以发现每个点向下的几条链中,最长链不会超过最短链的二倍
这是为什么呢
最长链,即为红黑交替,(保证性质4、5)
最短链,就是全黑了
那么黑高度相同,长链自然不会超过短链的二倍(其实这里不太严谨,应该是二倍+1,反正大概就是这样的)
举几个RBT栗子,来更好的认识RBT
违反性质1
违反性质2
违反性质4、5
正版红黑树
下面进入正题吧
\(\color{#9900ff}{定义}\)
enum Color{RED,BLACK};
struct node
{
//每个节点维护父亲,孩纸,颜色,大小,以及权值
node *fa,*ch[2];
int siz,val;
Color col;
//siz维护要判空!
void upd()
{
siz=1;
if(ch[0]) siz+=ch[0]->siz;
if(ch[1]) siz+=ch[1]->siz;
}
//下面的根Splay差不多
bool isr() { return fa->ch[1]==this;}
int rk() { return ch[0]? ch[0]->siz+1:1;}
};
RED,BLACK相当于两个变量,0/1,作为节点的颜色
前方高能!!
3
2
1
\(\color{#9900ff}{基本操作}\)
1、双红修正
这。。。名字居然是中文的。。。
因为这个操作不用单独写一个函数!
为什么呢? 因为这个操作只有在插入才会用到(毕竟插入会改变形态)
那删除呢?他不也会改变形态吗?
别急,那是操作二
根据操作的名字,大概脑补一下发生了什么qwq
首先,根据性质1,插入的节点必须要有颜色
那么我们到底给它什么颜色呢
如果给黑色的话, 很显然这条链的黑高度+1,那么整条链上所有的点都会受影响
但是如果我们插入红节点,首先性质5是一定不会因此而改变的
违反的性质越少,我们需要改变的也就越少,这也是我们所期望的,所以我们插入的点为红节点
但是我们要判断性质4的问题
这就是双红修正,解决的是插入之后违反性质4的问题
我们要分情况讨论
首先,如果插入点的父亲是黑节点,RBT性质显然是满足的,我们也不用做任何修改,直接return就行了qwq(这样绝对快(O(1)))
但是,如果插入点的父亲是红节点,怎么办呢
这时候就要双红修正了
注:以下,t为要恢复的节点,o为t的父亲,z为o的父亲,b为o的兄弟
有些图单独并不是红黑树,只是为了方便理解,部分子树没画
\(\color{#FF0099}{Case:1}\)
插入点父亲的兄弟b为红色
即下面左图所示
这时候我们要让B和C变黑,A变红(因为原树一定是满足性质的,所以A一定是黑色)
这是不难发现,子树A的缺陷没了!!!真的没了!!!
而且黑高度还没有变!!!
别高兴的太早
A变成了红色,它父亲要是红色咋办呢??
所以,这就成为了一个子问题,出问题的节点自然转变成了A,继续算法即可
那总得有个边界吧。
没错,就是到根节点
直接让根变黑可以满足所有性质
\(\color{#FF0099}{Case:2}\)
插入点父亲的兄弟b为黑色且z,o,t三点不是一条直线
我们需要把它们弄成一条直线,所以转o
左图为原来的情况,右图为转完后的情况,因为o是t的父亲,转完后,swap(o,t)
这样,问题转化为了第三种情况
\(\color{#FF0099}{Case:3}\)
插入点父亲的兄弟b为黑色且z,o,t三点是一条直线
这是后就好办了,现在是满足性质5的
我们让z变红,o变黑,会发生什么?
左面的黑高度-1
那么我们需要让左边共享右边的o
直接把o转上来就行了
而且因为o是黑的,所以一切都结束了qwq
双红修正完成!
void ins(int val)
{
//根为空特判,直接开新节点,一定注意根是黑的
if(root==NULL) {root=newnode(val);root->col=BLACK;return;}
//否则就开始插入了
nod o=root,t=newnode(val),z;
int k;
while(o->siz++,o->ch[k=(val>=o->val)]) o=o->ch[k];
//暴力找插入位置,沿途siz++
t->fa=o,o->ch[k]=t,o->upd();
//该维护的维护好,t是插入节点,也是可能要维护的第一个问题节点
//情况1的转化子问题过程,只要问题节点不是根(是根就根据情况1直接结束了)
//并且有问题(就是违反了性质4)
//那么就一直进行双红修正
while((o=t->fa)&&(o->col==RED))
{
//z是o的父亲
z=o->fa;
//判断儿子方向
int k1=o->isr(),k2=t->isr();
//b是兄弟
nod b=z->ch[!k1];
//先判b是否为空,然后如果是红色,那么就是情况1了
if(b&&b->col==RED)
{
//缺陷上传到z,当前问题节点为t=z,继续算法
b->col=o->col=BLACK;
z->col=RED,t=z;
continue;
}
//否则就是情况2或3
//如果是情况2,就需要旋转,把o转下去,别忘交换ot(上面说了)
if(k1^k2) rot(o,k1),std::swap(o,t);
//剩下的就是单纯的情况3了
//把z变红,o变黑,然后z转下去(即o转上来)
o->col=BLACK,z->col=RED;
rot(z,!k1);
}
//根的颜色为黑!!!!
root->col=BLACK;
}
上面一定要好好理解!
2、双黑修正
这是红黑树最cd的一段
首先先说删的方法,之后再说维护的问题
我们没有splay的旋转,也没有Treap的merge
那怎么删除?
想象一下,如果要删的点至少一个儿子为空,那么直接把另一个儿子接上来不就行了?
所以如果当前点两个儿子都有,我们可以找它的后继
因为是后继,所以它至少是没有左孩子的,也就符合刚刚的条件
于是把它后继的值给当前点,然后问题就转化为删它的后继了
这就是删除的方式
然后我们考虑维护性质
因为我们不能保证删的点是红节点啊
所以恶心的性质5就可能出锅
如果删的节点使红节点,那就简单了,因为不会影响任何红黑树的性质,算法直接结束
算是O(1)删除了吧qwq
要是删的是黑节点。。。。就有问题了。。。。
下面讨论删的是黑节点的情况
既然删了一个黑节点,显然它所在链黑高度--
而第5性质恰恰是不好维护的
我们不妨转化一下
当我们将黑节点x删除时,强制将其的黑色压到齐孩子节点上
而且孩子节点原来的颜色依然存在
这样就违反了性质1,但是性质5却成立了
那么现在就想办法去掉那一层颜色
\(\color{#FF0099}{Case:1}\)
x一层红,一层黑
显然直接去掉那一层红是不影响性质的qwq
\(\color{#FF0099}{Case:2.1}\)
x是黑+黑且为根节点
这时我们去掉一层黑,让所有黑高度-1,依然不会违反性质,成立!
\(\color{#FF0099}{Case:2.2.0}\)
这个麻烦了
x是黑+黑且不是根
我们将其分为了4种情况
\(\color{#FF0099}{Case:2.2.1}\)
x的兄弟为红,那么显然x的父亲,x兄弟的儿子一定都是黑的(性质4)
我们把z染红,b染黑,然后把b转上来
这时候情况转化为了下面三种情况之一
当然不要忘了b是o的兄弟,旋转之后要把更新b指向的节点L
\(\color{#FF0099}{Case:2.2.2}\)
兄弟为黑色,兄弟的两个儿子全是黑色
这时可以把那一重黑色上移到z节点上
于是b要改变成红色,因为b的路径上多了一个黑高度
对于在z上的那个黑色,此时显然z就是违反性质1的节点,我们下次只需让o=z,继续子问题即可
而此时,如果z是红色,那就是红+黑问题了啊,就直接结束了qwq
上图的绿色代表可以是任意颜色(红/黑)
\(\color{#FF0099}{Case:2.2.3}\)
兄弟为黑,兄弟的d儿子为红色,!d儿子为黑色
注:d是o是父亲的哪个儿子,也就是说o是父亲的哪个儿子,b的哪个儿子就是红色,另一个就是黑色
这时我们把b染红,把d孩子染黑,然后把d孩子转上去,就转化为了情况4
\(\color{#FF0099}{Case:2.2.4}\)
兄弟为黑,兄弟的!d儿子为红色
这时我们把b转上来,然后可以发现,原来的z和原来的b的!d孩子都是红色,这是一个机会!!
我们可以做一个神奇的操作来去掉o上的黑色!
我们把那两个红色的点变黑,上面那个黑点变红,即黑色下放到两个子树
用下图的左边与右边对比一下,左子树多了一个黑!!!
这时候,我们去掉一个黑,也就是那一重黑,不就行了?
为了方便,这是可以直接把o=root,下次循环就出去了
上面非常重要,是红黑树的精髓!
这么cd的东西,代码肯定不会短
记得参考的代码好像有200行。。。
//o是双黑节点,z是o的父亲,因为o可能是NULL,所以防止判断左右儿子的时候RE,传进了一个父亲参数
void fix(nod o,nod z)
{
//兄弟节点b
nod b;
//只要o是黑的(不管空不空,它是双黑的qwq)并且o不是根
while((!o||o->col==BLACK)&&o!=root)
{
//k就是儿子的方向
bool k=z->ch[1]==o;
//确认兄弟节点
b=z->ch[!k];
//双黑情况1,兄弟为红,该换色的换色,然后旋转,别忘了更新b!这样情况转为2/3/4
if(b->col==RED) b->col=BLACK,z->col=RED,rot(z,k),b=z->ch[!k];
//如果兄弟的儿子全黑,则为双黑情况2,染红b(黑色上移),双黑节点变为z,所以o=z
//这时候如果o是红的(就是原来z是红的,就是黑+红的情况,直接变黑就行,在while中结束,下面染黑)
if((!b->ch[0]||b->ch[0]->col==BLACK)&&(!b->ch[1]||b->ch[1]->col==BLACK)) b->col=RED,o=z,z=o->fa;
else
{
//这就是说明兄弟有红儿子了
//如果!k是黑,显然k就是红了,这就是双黑情况3
if(!b->ch[!k]||b->ch[!k]->col==BLACK) b->ch[k]->col=BLACK,b->col=RED,rot(b,!k),b=z->ch[!k];
//情况3会转化为情况4,这是直接break,因为o=root(其实不写break也一样)
b->col=z->col,z->col=BLACK,b->ch[!k]->col=BLACK,rot(z,k);
o=root;
break;
}
}
//只要不空就染黑(根据上面所述)
if(o) o->col=BLACK;
}
//找到权为k的点
nod sch(const int &k)
{
nod o=root;
while(o&&o->val!=k) o=o->ch[k>=o->val];
return o;
}
//删除权为val的点
void del(const int &val)
{
nod o=root,z,f,p,g;
Color tmp;
//树中都没这个点,还删个毛线,返回就行了
if(sch(val)==NULL) return;
//否则就往下找,沿途siz--(因为要删一个点)
while(o&&o->val!=val) o->siz--,o=o->ch[val>=o->val];
o->siz--;
//如果它两个孩子都有,那么根据前面所说,我们要删它后继
if(o->ch[0]&&o->ch[1])
{
//p是它后继,z是它父亲,
p=o->ch[1],z=o->fa;
//让p找到它父亲,显然p没有左孩子(右孩子不一定有)
while(p->ch[0]) p->siz--,p=p->ch[0];
//认儿子,注意判根(把o删了,p接上)
if(z) z->ch[o->isr()]=p;
else root=p;
//删p,要把它的孩子接上,g就是那个孩子(可能为空)
//现在要把g接在f上
g=p->ch[1],f=p->fa,tmp=p->col;
//特盘直接相连的情况
if(f==o) f=p;
else
{
//认父亲,认儿子
if(g) g->fa=f;
f->ch[0]=g,p->ch[1]=o->ch[1],o->ch[1]->fa=p;
//更新siz
f->upd();
}
//这是把原来o的东西全给p(相当于让p取代了o,而原来的p(后继)也因g与f相接而不复存在了)
p->siz=o->siz,p->fa=z,p->col=o->col,p->ch[0]=o->ch[0],o->ch[0]->fa=p;
//如果是黑色在进入双黑修正
if(tmp==BLACK) fix(g,f);
//删掉o就行了
st[top++]=o;
}
else
{
//o本身有空儿子,就让p的o的不空的儿子来接上z
p=o->ch[o->ch[1]!=NULL];
z=o->fa,tmp=o->col;
//pz父子相认(由爷孙变成父子)
if(p) p->fa=z;
if(z) z->ch[o->isr()]=p;
else root=p;
//如果原色为黑,则因为又来了个黑,就双黑修正
if(tmp==BLACK) fix(p,z);
//删o
st[top++]=o;
}
}
\(\color{#9900ff}{其它操作}\)
插入删除上面都说了,就不解释了
由于其它的操作跟基本操作没关系了,所以近乎暴力查找qwq
int nxt(int val)
{
int ans=inf;
nod t=root;
while(t)
{
if(val>=t->val)t=t->ch[1];
else ans=std::min(ans,t->val),t=t->ch[0];
}
return ans;
}
int pre(int val)
{
int ans=-inf;
nod t=root;
while(t)
{
if(val<=t->val)t=t->ch[0];
else ans=std::max(ans,t->val),t=t->ch[1];
}
return ans;
}
int rnk(int x)
{
int ans=1;
nod o=root;
while(o)
{
if(o->val<x) ans+=o->rk(),o=o->ch[1];
else o=o->ch[0];
}
return ans;
}
int kth(int k)
{
nod o=root;
int num;
while((num=o->rk())!=k)
{
if(num<k)k-=num,o=o->ch[1];
else o=o->ch[0];
}
return o->val;
}
这就是神奇的红黑树qwq
放下完整代码(网上找了好久,都是从STL等地扒的,研究了好久)
#include<cstdio>
#include<queue>
#include<vector>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cmath>
#define _ 0
#define LL long long
#define Space putchar(' ')
#define Enter putchar('\n')
#define fuu(x,y,z) for(int x=(y),x##end=z;x<=x##end;x++)
#define fu(x,y,z) for(int x=(y),x##end=z;x<x##end;x++)
#define fdd(x,y,z) for(int x=(y),x##end=z;x>=x##end;x--)
#define fd(x,y,z) for(int x=(y),x##end=z;x>x##end;x--)
#define mem(x,y) memset(x,y,sizeof(x))
#ifndef olinr
inline char getc()
{
static char buf[100001],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100001,stdin),p1==p2)? EOF:*p1++;
}
#else
#define getc() getchar()
#endif
inline int in()
{
int f=1,x=0; char ch;
while(!isdigit(ch=getc()))(ch=='-')&&(f=-f);
while(isdigit(ch)) x=x*10+(ch^48),ch=getc();
return x*f;
}
enum Color{RED,BLACK};
struct node
{
node *fa,*ch[2];
int siz,val;
Color col;
void upd()
{
siz=1;
if(ch[0]) siz+=ch[0]->siz;
if(ch[1]) siz+=ch[1]->siz;
}
bool isr() { return fa->ch[1]==this;}
int rk() { return ch[0]? ch[0]->siz+1:1;}
};
typedef node* nod;
nod st[105050],root;
int top;
const int inf=0x7fffffff;
nod newnode(int val)
{
static node s[105050],*tail=s;
nod o=top? st[--top]:tail++;
o->fa=o->ch[0]=o->ch[1]=NULL;
o->siz=1,o->val=val,o->col=RED;
return o;
}
void rot(nod x,bool k)
{
nod y=x->ch[!k],z=x->fa;
x->ch[!k]=y->ch[k];
if(y->ch[k]) y->ch[k]->fa=x;
y->fa=z;
if(z) z->ch[x->isr()]=y;
else root=y;
y->ch[k]=x,x->fa=y;
x->upd(),y->upd();
}
void ins(int val)
{
if(root==NULL) {root=newnode(val);root->col=BLACK;return;}
nod o=root,t=newnode(val),z;
int k;
while(o->siz++,o->ch[k=(val>=o->val)]) o=o->ch[k];
t->fa=o,o->ch[k]=t,o->upd();
while((o=t->fa)&&(o->col==RED))
{
z=o->fa;
int k1=o->isr(),k2=t->isr();
nod b=z->ch[!k1];
if(b&&b->col==RED)
{
b->col=o->col=BLACK;
z->col=RED,t=z;
continue;
}
if(k1^k2) rot(o,k1),std::swap(o,t);
o->col=BLACK,z->col=RED;
rot(z,!k1);
}
root->col=BLACK;
}
nod sch(const int &k)
{
nod o=root;
while(o&&o->val!=k) o=o->ch[k>=o->val];
return o;
}
void fix(nod o,nod z)
{
nod b;
while((!o||o->col==BLACK)&&o!=root)
{
bool k=z->ch[1]==o;
b=z->ch[!k];
if(b->col==RED) b->col=BLACK,z->col=RED,rot(z,k),b=z->ch[!k];
if((!b->ch[0]||b->ch[0]->col==BLACK)&&(!b->ch[1]||b->ch[1]->col==BLACK)) b->col=RED,o=z,z=o->fa;
else
{
if(!b->ch[!k]||b->ch[!k]->col==BLACK) b->ch[k]->col=BLACK,b->col=RED,rot(b,!k),b=z->ch[!k];
b->col=z->col,z->col=BLACK,b->ch[!k]->col=BLACK,rot(z,k);
o=root;
break;
}
}
if(o) o->col=BLACK;
}
void del(const int &val)
{
nod o=root,z,f,p,g;
Color tmp;
if(sch(val)==NULL) return;
while(o&&o->val!=val) o->siz--,o=o->ch[val>=o->val];
o->siz--;
if(o->ch[0]&&o->ch[1])
{
p=o->ch[1],z=o->fa;
while(p->ch[0]) p->siz--,p=p->ch[0];
if(z) z->ch[o->isr()]=p;
else root=p;
g=p->ch[1],f=p->fa,tmp=p->col;
if(f==o) f=p;
else
{
if(g) g->fa=f;
f->ch[0]=g,p->ch[1]=o->ch[1],o->ch[1]->fa=p;
f->upd();
}
p->siz=o->siz,p->fa=z,p->col=o->col,p->ch[0]=o->ch[0],o->ch[0]->fa=p;
if(tmp==BLACK) fix(g,f);
st[top++]=o;
}
else
{
p=o->ch[o->ch[1]!=NULL];
z=o->fa,tmp=o->col;
if(p) p->fa=z;
if(z) z->ch[o->isr()]=p;
else root=p;
if(tmp==BLACK) fix(p,z);
st[top++]=o;
}
}
int nxt(int val)
{
int ans=inf;
nod t=root;
while(t)
{
if(val>=t->val)t=t->ch[1];
else ans=std::min(ans,t->val),t=t->ch[0];
}
return ans;
}
int pre(int val)
{
int ans=-inf;
nod t=root;
while(t)
{
if(val<=t->val)t=t->ch[0];
else ans=std::max(ans,t->val),t=t->ch[1];
}
return ans;
}
int rnk(int x)
{
int ans=1;
nod o=root;
while(o)
{
if(o->val<x) ans+=o->rk(),o=o->ch[1];
else o=o->ch[0];
}
return ans;
}
int kth(int k)
{
nod o=root;
int num;
while((num=o->rk())!=k)
{
if(num<k)k-=num,o=o->ch[1];
else o=o->ch[0];
}
return o->val;
}
int main()
{
int n=in();
while(n--)
{
int op=in();
if(op==1)ins(in());
if(op==2)del(in());
if(op==3)printf("%d\n",rnk(in()));
if(op==4)printf("%d\n",kth(in()));
if(op==5)printf("%d\n",pre(in()));
if(op==6)printf("%d\n",nxt(in()));
}
return 0;
}
平衡树学习笔记(6)-------RBT的更多相关文章
- 平衡树学习笔记(5)-------SBT
SBT 上一篇:平衡树学习笔记(4)-------替罪羊树 所谓SBT,就是Size Balanced Tree 它的速度很快,完全碾爆Treap,Splay等平衡树,而且代码简洁易懂 尤其是插入节点 ...
- 平衡树学习笔记(3)-------Splay
Splay 上一篇:平衡树学习笔记(2)-------Treap Splay是一个实用而且灵活性很强的平衡树 效率上也比较客观,但是一定要一次性写对 debug可能不是那么容易 Splay作为平衡树, ...
- 平衡树学习笔记(2)-------Treap
Treap 上一篇:平衡树学习笔记(1)-------简介 Treap是一个玄学的平衡树 为什么说它玄学呢? 还记得上一节说过每个平衡树都有自己的平衡方式吗? 没错,它平衡的方式是......rand ...
- BST,Splay平衡树学习笔记
BST,Splay平衡树学习笔记 1.二叉查找树BST BST是一种二叉树形结构,其特点就在于:每一个非叶子结点的值都大于他的左子树中的任意一个值,并都小于他的右子树中的任意一个值. 2.BST的用处 ...
- 普通平衡树学习笔记之Splay算法
前言 今天不容易有一天的自由学习时间,当然要用来"学习".在此记录一下今天学到的最基础的平衡树. 定义 平衡树是二叉搜索树和堆合并构成的数据结构,它是一 棵空树或它的左右两个子树的 ...
- 浅谈树套树(线段树套平衡树)&学习笔记
0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...
- [学习笔记]平衡树(Splay)——旋转的灵魂舞蹈家
1.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...
- [学习笔记]可持久化数据结构——数组、并查集、平衡树、Trie树
可持久化:支持查询历史版本和在历史版本上修改 可持久化数组 主席树做即可. [模板]可持久化数组(可持久化线段树/平衡树) 可持久化并查集 可持久化并查集 主席树做即可. 要按秩合并.(路径压缩每次建 ...
- 平衡树splay学习笔记#2
讲一下另外的所有操作(指的是普通平衡树中的其他操作) 前一篇的学习笔记连接:[传送门],结尾会带上完整的代码. 操作1,pushup操作 之前学习过线段树,都知道子节点的信息需要更新到父亲节点上. 因 ...
随机推荐
- 基于OpenCV的火焰检测(三)——HSI颜色判据
上文向大家介绍了如何用最简单的RGB判据来初步提取火焰区域,现在我要给大家分享的是一种更加直观的判据--HSI判据. 为什么说HSI判据是更加直观的判据呢?老规矩,先介绍一下HSI色彩模型: HSI颜 ...
- java--构造器与static
原本无显示编码构造器,则有一个默认的隐式(隐藏的无参构造器),但是,当显示指定了构造器,则这个默认隐式的构造器将不存在,比如此时无法new无参的构造器(除非显示地编写声明无参的构造函数). 如果子类构 ...
- C语言生成程序问题
问题: 我用VS2013写好C语言程序调试运行后就在debug文件夹下生成了EXE文件,可以在本机运行.但是这个EXE文件在别的没装过VS2013的电脑上就不能直接运行,说丢失MSVCR120D.dl ...
- 安装 MongoDB。
1.安装 MongoDB. 1.为软件包管理系统导入公钥. Ubuntu 软件包管理工具为了保证软件包的一致性和可靠性需要用 GPG 密钥检验软件包.使用下列命令导入 MongoDB 的 GPG 密钥 ...
- Eclipse中,将jar包导入为User Library
项目右键 Properties -> bulid path -> Add Library -> User Library -> User Libraries -> New ...
- memset,memcpy,strcpy的使用与区别
1.memset 原型: extern void *memset(void *buffer, int c, int count); 功能: 把buffer所指内存区域的前count个字节设置成 ...
- C++的继承与接口
1.继承方式 三种继承方式,public,private,protected.注意,继承方式是相对于某一层类的方法而言,并不是相对于子类的对象而言.对于外部世界()对象来说,protected和pri ...
- ActiveMQ (二) JMS入门
JMS入门 前提:安装好了ActiveMQ ActiveMQ安装 Demo结构: 首先pom.xml引入依赖: <dependency> <groupId>org.apach ...
- MyBatis配置Setting详细说明
该表格转载自http://blog.csdn.net/summer_yuxia/article/details/53169227 setting是指定MyBatis的一些全局配置属性,这是MyBati ...
- iBase4J项目笔记
目录: 1 数据库密码加密 2 service层概述 3 web层概述 4 后端CRUD 4.1 READ 4.2 UPDATE 4.3 CREATE 4.4 DELETE 5 facade层概述 1 ...