RBT

上一篇:平衡树学习笔记(5)-------SBT

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的更多相关文章

  1. 平衡树学习笔记(5)-------SBT

    SBT 上一篇:平衡树学习笔记(4)-------替罪羊树 所谓SBT,就是Size Balanced Tree 它的速度很快,完全碾爆Treap,Splay等平衡树,而且代码简洁易懂 尤其是插入节点 ...

  2. 平衡树学习笔记(3)-------Splay

    Splay 上一篇:平衡树学习笔记(2)-------Treap Splay是一个实用而且灵活性很强的平衡树 效率上也比较客观,但是一定要一次性写对 debug可能不是那么容易 Splay作为平衡树, ...

  3. 平衡树学习笔记(2)-------Treap

    Treap 上一篇:平衡树学习笔记(1)-------简介 Treap是一个玄学的平衡树 为什么说它玄学呢? 还记得上一节说过每个平衡树都有自己的平衡方式吗? 没错,它平衡的方式是......rand ...

  4. BST,Splay平衡树学习笔记

    BST,Splay平衡树学习笔记 1.二叉查找树BST BST是一种二叉树形结构,其特点就在于:每一个非叶子结点的值都大于他的左子树中的任意一个值,并都小于他的右子树中的任意一个值. 2.BST的用处 ...

  5. 普通平衡树学习笔记之Splay算法

    前言 今天不容易有一天的自由学习时间,当然要用来"学习".在此记录一下今天学到的最基础的平衡树. 定义 平衡树是二叉搜索树和堆合并构成的数据结构,它是一 棵空树或它的左右两个子树的 ...

  6. 浅谈树套树(线段树套平衡树)&学习笔记

    0XFF 前言 *如果本文有不好的地方,请在下方评论区提出,Qiuly感激不尽! 0X1F 这个东西有啥用? 树套树------线段树套平衡树,可以用于解决待修改区间\(K\)大的问题,当然也可以用 ...

  7. [学习笔记]平衡树(Splay)——旋转的灵魂舞蹈家

    1.简介 首先要知道什么是二叉查找树. 这是一棵二叉树,每个节点最多有一个左儿子,一个右儿子. 它能支持查找功能. 具体来说,每个儿子有一个权值,保证一个节点的左儿子权值小于这个节点,右儿子权值大于这 ...

  8. [学习笔记]可持久化数据结构——数组、并查集、平衡树、Trie树

    可持久化:支持查询历史版本和在历史版本上修改 可持久化数组 主席树做即可. [模板]可持久化数组(可持久化线段树/平衡树) 可持久化并查集 可持久化并查集 主席树做即可. 要按秩合并.(路径压缩每次建 ...

  9. 平衡树splay学习笔记#2

    讲一下另外的所有操作(指的是普通平衡树中的其他操作) 前一篇的学习笔记连接:[传送门],结尾会带上完整的代码. 操作1,pushup操作 之前学习过线段树,都知道子节点的信息需要更新到父亲节点上. 因 ...

随机推荐

  1. 1104 Sum of Number Segments

    题意: 给出n个不大于1.0的小数序列,如{ 0.1, 0.2, 0.3, 0.4 },则共有10个分片(0.1) (0.1, 0.2) (0.1, 0.2, 0.3) (0.1, 0.2, 0.3, ...

  2. spring学习七

    一: web.xml中常用配置元素? <servlet></servlet>: 在向servlet或JSP页面制定初始化参数或定制URL时,首先命名servlet或JSP页面. ...

  3. 2015.3.31不使用debug/X86文件夹方式解决64/32位问题

    传统方法:在解决方案-配置管理器-新建X86平台可以解决32位兼容问题,但是Debug目录下会多出X86文件夹.不方便 另一种方法:在项目名称-属性-生成-目标平台-x86也能解决问题,而且不出现X8 ...

  4. #关于 OneVsRestClassifier(LogisticRegression(太慢了,要用超过的机器)

    #关于 OneVsRestClassifier #注意以下代码中,有三个类 from sklearn import datasets X, y = datasets.make_classificati ...

  5. java代码调用数据库存储过程

    由于前边有写java代码调用数据库,感觉应该把java调用存储过程也写一下,所以笔者补充该篇! package testSpring; import java.sql.CallableStatemen ...

  6. HTML标签详细讲解

    http://www.cnblogs.com/yuanchenqi/articles/5603871.html

  7. java中用正则表达式判断中文字符串中是否含有英文或者数字

    public static boolean includingNUM(String str)throws  Exception{ Pattern p  = Pattern.compile(" ...

  8. git安装、git和GitHub的配合使用、git和码云的配合使用

    1 git安装请参见廖雪松的git教程前面几节 点击前往 2 git速成之基本命令 点击前往 3 git 和 GitHub 配合使用之基础 点击前往 4 git 和 GitHub 配合使用之进阶 点击 ...

  9. Luogu 3521 [POI2011]ROT-Tree Rotations

    BZOJ 2212 从下到上线段树合并. 考虑到每一个子树内部产生的贡献不可能通过换儿子消除,所以一次更换只要看看把哪个儿子放在左边产生的逆序对数少就可以了. 逆序对数可以在线段树合并的时候顺便算出来 ...

  10. 第二篇:MySQL库相关操作

    一 系统数据库 information_schema: 虚拟库,不占用磁盘空间,存储的是数据库启动后的一些参数,如用户表信息.列信息.权限信息.字符信息等performance_schema: MyS ...