您的位置:首页 > 其它

《算法导论》笔记(5)链表到红黑树

2015-02-05 11:28 525 查看
基本数据结构:链表,队列,散列表,二叉树,红黑树。

栈和队列都是抽象的结构,不一定是物理连续的内存空间。但必须实现push()和pop()的抽象接口。链表有单、双向链表和循环链表。可按照iterator++或者iterator--的方式访问。另外要注意的是插入或删除时对指针的操作。某些语言不支持指针和对象,那么实现链表有2种方式。多维数组或1维数组。多维数组的实现方式是A[i][j][k]中的j、k分别指向前驱和后继的i下标。一维数组则将一小段连续的内存作为一个对象,起始的3个整数分别是i、j、 k。

树是每个结点有除根结点外有一个父结点与任意个子结点,父子结点以指针链接的数据结构。另一种结构是左孩子右兄弟表示法。略。

散列表。直接寻址表。冲突的解决方法:链接法,开放寻址表。散列函数的作用是将关键字生成散列值以放入槽中。散列函数有乘法、除法,以及增加随机性的全域散列法。有一个全域散列法的实例。hab(k)=((ak+b)mod p) mod m。其中a、b<p, p是素数,共同定义了全域的散列函数簇。均匀的选择a、b,得到两个不同的散列值之差也是均匀分布的。

开放寻址表的优点是所有的储存空间都作为槽,实际上增加了槽的数量,潜在的减少冲突。在不需要删除元素时是很方便的。若要删除元素,可以将删除后的空格作特殊标记,查找时不会跳过,而插入时可以插入。开放寻址表探查序列有3种方法:线性探查、二次探查、双重散列。开放寻址的插入操作最多探查次数是1(1-a),a为装载因子。成功查找的探查次数期望值为1/a*ln(1/(1-a)),不成功查找的探查次数期望值为1/(1-a)。最后介绍了完全散列。先将全部n个元素散列到m个槽,然后将每个槽里冲突的元素重新散列到大小mj=nj^2的二级散列表中。

二叉搜索树。中序、先序、后序遍历,查找,插入,删除。

in_walk(x){if x==null return; in_walk(x.left); visit(x); in_walk(x.right);}
pre_walk(x){if x==null return; visit(x); pre_walk(x.left); pre_walk(x.right);}
post_walk(x){if x==null return; post_walk(x.left); post_walk(x.right); visit(x);}
search(k,x){if x.value==k or x==null return; if x.value<k return search(x.left); return search(x.right);}
insert(k,x){
if (k<x.value{
if (x.left!=null) {insert(k,x.left); }
else {k=new node(k, x.left.left); }
}
if (k>x.value){
if (x.right!=null) {insert (k, x.right); }
else {k=new node(k, x.right.right); }
}
return k;
}
delete(x){
if (x.left==null x.right==null) {delete x and return x.p;}
else {y= <span style="font-family: Arial, Helvetica, sans-serif;">minimum_tree(x.right)</span><span style="font-family: Arial, Helvetica, sans-serif;">; transplant(x, y</span><span style="font-family: Arial, Helvetica, sans-serif;">) and return y; } </span>
}
transplant(x,y){
x.value=y.value;
if(y.right==null) {delete y and return y.p;} else {y=y.right and return y;}
}

红黑树。特征:根黑,红结点子黑,路径上黑点数相同。左旋、右旋,插入、删除。

自然语言描述插入过程:插入,涂红,判断1:父结点在左叔在右,判断2:若叔红则父叔同变黑,祖变红,游标上升到祖,回到判断2若叔黑,判断3:子在父右则先左旋转将父变左子,判断3结束,父变黑,祖变红,右旋转,父升祖降。回到判断1,若父右叔左,左右颠倒后相同过程重复一遍。

自然语言描述删除过程:待删除点为z,判断1:z是否有左右叶结点,若只有一个,删除z,拼接子结点,若有2个叶结点,y=minimum_tree(z.r),置换z、y包括颜色,fix()调整颜色。fix()过程描述:判断1:若在父左,判断2,若弟红父黑,左旋父,父变红,弟变黑祖,判断3:若弟黑两子黑,父加黑,弟变红,游标上升到父,回判断3,若弟黑左子红右子黑,弟与其左子交换颜色,弟右旋,回判断3:若弟黑右子红,弟与父交换颜色,父左旋。所谓插入看叔,删除看侄。插入时r(rbr)->r(brb)、r(rbb)->(rbr)b;删除时(bbr)bb->bb(rbb) (bub)bb->(bbr)bb (bub)rb->(bub)r (bub)r->b(bub)

在实际应用时,要注意赋值时的深浅拷贝问题,因为每个对象含有数个指针或引用。另外Java函数传参数时,是把实参引用的对象赋给形参引用,函数体中对形参的操作不会影响到实参,除了对象方法的调用。而C/C++可以引用或者指针传递,操作都会反映到实参的对象。另外一个要注意的点就是不要把临时对象的指针给返回到函数外。

left_rotate(x, y=x.r){
move x to x.l;
move y.r to x.l;
move y to x;
}

right_rotate(x, y=x.l){
move x to x.r;
move y.r to x.l;
move y to x;
}

RB_insert(k)
{
x=insert(k);
x.color=red;
if(x.p.color==red) fix_insert(x);
}

fix_insert(x){
while(x.p==x.p.p.left) {
if (x.p.p.right.color==red){ x.p.color=black; x.p.p.right.color=black; x.p.p.color=red; x=x.p.p;}
else {
if (x==x.p.right){ left_rotate(x.p); x=x.left;}
else {x.p.color=b; x.p.p.color=r; right_rotate(x.p.p); return;}
}
}
while(x.p==x.p.p.right) {
if (x.p.p.left.color==red){ x.p.color=black; x.p.p.left.color=black; x.p.p.color=red; x=x.p.p;}
else {
if (x==x.p.left){ right_rotate(x.p); x=x.right;}
else {x.p.color=b; x.p.p.color=r; left_rotate(x.p.p); return;}
}
}
if x==root {x.color=r; return;}
if x.p==root return;
}

RB_delete(k){
color1=k.color;
x=delete(k);
if(color1==r) return;
if (x.color==r && k.color==b) x.color=b; return;
if (x.color==b && k.color==b) fix_delete(x);
}

fix_delete(){
while(x==x.p.left) {
if (x.p.right.color==red){ x.p.color=r; x.p.right.color=black; left_rotate(x.p); }
else {
if (x.p.right.left.color==b && x.p.right.right.color==b) { x.p.right.color=r; if (x.p.color==r) {x.p.color=b;return;} else x=x.p;}
else if(x.p.right.left.color==r && x.p.right.right.color==b) {x.p.right.color=r; x.p.right.left=b; right_rotate(x.p.right);}
else if(x.p.right.right.color==r){ x.p.right.color=x.p.color; x.p.color=b; x.p.right.right.color=b; left_rotate(x.p); return;}
}
}
while(x==x.p.right) {
if (x.p.left.color==red){ x.p.color=r; x.p.left.color=black; right_rotate(x.p); }
else {
if (x.p.left.right.color==b && x.p.left.left.color==b) { x.p.left.color=r; if (x.p.color==r) {x.p.color=b;return;} else x=x.p;}
else if(x.p.left.right.color==r && x.p.left.left.color==b) {x.p.left.color=r; x.p.left.right=b; left_rotate(x.p.left);}
else if(x.p.left.left.color==r){ x.p.left.color=x.p.color; x.p.color=b; x.p.left.left.color=b; right_rotate(x.p); return;}
}
}
if x==root return;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: