一,二叉排序树
1.结构定义
2.结构操作
(1)节点
插入
-
从根节点开始,逐层比较
-
要插入的节点比当前节点大,指针往右子树移
-
要插入的节点比当前节点小,指针往左子树移
-
直到遍历到空节点,根据上述规则,插入到空节点
(2)节点删除
1、删除叶
⼦节点
-
直接删除
2、删除出度为1的节点
-
提升唯一的子树
3、删除出度为2的节点
-
找到要删除节点的前驱或者后继,与其中之一替换后,转换为度为1的节点问题
前驱:从要删除的节点的左子树开始,向右遍历到的最大节点为要删除的节点的前驱
后继:从要删除的节点的右子树开始,向左遍历到的最小节点为要删除的节点的后继
代码实现:
#include
<iostream>
#include
<cstdio>
#include
<ctime>
#include
<cstdlib>
using
namespace
std;
#define
KEY(n) (n ? n->key : -1)
typedef
struct
Node {
int
key;
struct
Node* lchild, * rchild;
}Node;
Node* getNewNode(
int
key) {
Node* p = (Node*)malloc(
sizeof
(Node));
p->key = key;
p->lchild = p->rchild = NULL;
return
p;
}
//插入,返回当前子树根节点
Node* insert(
Node
*
root
,
int
key
) {
if
(
root
==
NULL
)
return
getNewNode(
key
);
if
(
root
->key ==
key
)
return
root
;
if
(
key
>
root
->key)
root
->rchild = insert(
root
->rchild,
key
);
else
root
->lchild = insert(
root
->lchild,
key
);
return
root
;
}
Node
* predecessor(
Node
*
root
) {
Node
* temp =
root
->lchild;
while
(temp->rchild)temp = temp->rchild;
return
temp;
}
//删除,返回当前子树根节点
Node
* erase(
Node
*
root
,
int
key
) {
if
(
root
==
NULL
)
return
root
;
if
(
key
<
root
->key)
root
->lchild = erase(
root
->lchild,
key
);
else
if
(
key
>
root
->key)
root
->rchild = erase(
root
->rchild,
key
);
else
{
//要删除节点出度为0的节点
if
(
root
->rchild ==
NULL
&&
root
->lchild ==
NULL
) {
free(
root
);
//返回给父节点指针
return
NULL
;
}
//要删除节点出度为1的节点
else
if
(
root
->lchild ==
NULL
||
root
->rchild ==
NULL
) {
Node
* temp =
root
->lchild ?
root
->lchild :
root
->rchild;
free(
root
);
return
temp;
}
//要删除节点出度为2的节点
else
{
Node
* temp = predecessor(
root
);
root
->key = temp->key;
root
->lchild = erase(
root
->lchild, temp->key);
}
}
return
root
;
}
void
clear(
Node
*
root
) {
if
(
root
==
NULL
)
return
;
clear(
root
->lchild);
clear(
root
->rchild);
free(
root
);
return
;
}
//前序遍历
void
output(
Node
*
root
) {
if
(
root
==
NULL
)
return
;
printf(
"(%d ; %d, %d)\n"
,
KEY
(
root
),
KEY
(
root
->lchild),
KEY
(
root
->rchild)
);
output(
root
->lchild);
output(
root
->rchild);
return
;
}
//中序遍历
void
in_order(
Node
*
root
) {
if
(
root
==
NULL
)
return
;
in_order(
root
->lchild);
printf(
"%d "
,
root
->key);
in_order(
root
->rchild);
return
;
}
int
main() {
srand(time(0));
#define
MAX_OP
10
Node
* root =
NULL
;
for
(
int
i = 0; i <
MAX_OP
; i++) {
int
key = rand() % 100;
printf(
"insert key %d to BST\n"
, key);
root = insert(root, key);
}
output(root);
printf(
"in order : "
);
in_order(root);
printf(
"\n"
);
int
x;
while
(~scanf_s(
"%d"
, &x)) {
printf(
"erase %d from BST\n"
, x);
root = erase(root, x);
in_order(root); printf(
"\n"
);
}
return
0;
}
二,AVL树
1.k1为从下往上看的第一个失衡的位置(k1左右子树的高度差大于1)
2.LL型k1的左子树要更高,k1的左子树的左子树要更高(和各自的右子树相比)
RL型 -->先小右旋,在大左旋
代码演示:
#include
<iostream>
#include
<cstdio>
#include
<ctime>
#include
<cmath>
#include
<cstdlib>
using
namespace
std;
typedef
struct
Node
{
int
key, h;
struct
Node
* rchild, * lchild;
}
Node
;
//创建虚拟空节点
Node
__NIL;
#define
NIL
(&__NIL)
#define
K
(n) (n->key)
#define
H
(n) (n->h)
#define
L
(n) (n->lchild)
#define
R
(n) (n->rchild)
//初始化虚拟空节点
__attribute__((constructor));
void
init__NIL() {
K
(
NIL
) = -1;
H
(
NIL
) = 0;
L
(
NIL
) =
R
(
NIL
) =
NIL
;
return
;
}
Node
* getNewNode(
int
key
) {
Node
* p = (
Node
*)malloc(
sizeof
(
Node
));
p->key =
key
;
p->h = 1;
p->lchild = p->rchild =
NIL
;
return
p;
}
//更新根节点的高度
void
update_height(
Node
*
root
) {
H
(
root
) = (
H
(
L
(
root
)) >
H
(
R
(
root
)) ?
H
(
L
(
root
)) :
H
(
R
(
root
))) + 1;
return
;
}
//左旋
Node
* left_rotate(
Node
*
root
) {
printf(
"left rotate : %d\n"
,
root
->key);
Node
* new_node =
root
->rchild;
root
->rchild = new_node->lchild;
new_node->lchild =
root
;
update_height(
root
);
update_height(new_node);
return
new_node;
}
//右旋
Node
* right_rotate(
Node
*
root
) {
printf(
"right rotate : %d\n"
,
root
->key);
Node
* new_node =
root
->lchild;
root
->lchild = new_node->rchild;
new_node->rchild =
root
;
update_height(
root
);
update_height(new_node);
return
new_node;
}
//维护类型--失衡类型
const
char
* type_str[5] = {
""
,
"maintain type : LL"
"maintain type : LR"
"maintain type : RR"
"maintain type : RL"
};
//维护平衡状态
Node
* maintain(
Node
*
root
) {
//不用维护
if
(abs(
H
(
L
(
root
)) -
H
(
R
(
root
))) <= 1)
return
root
;
//记录失衡类型
int
type = 0;
if
(
H
(
L
(
root
)) >
H
(
R
(
root
))) {
if
(
H
(
R
(
L
(
root
))) >
H
(
L
(
L
(
root
)))) {
// LR --> 小左旋
root
->lchild = left_rotate(
root
->lchild);
type += 1;
}
// LL/LR --> 大右旋
root
= right_rotate(
root
);
type += 1;
}
else
{
if
(
H
(
L
(
R
(
root
))) >
H
(
R
(
R
(
root
)))) {
//RL --> 小右旋
root
->rchild = right_rotate(
root
->rchild);
type += 1;
}
// RR/RL --> 大左旋
root
= left_rotate(
root
);
type += 1;
}
printf(
"%s\n"
, type_str[type]);
return
root
;
}
Node
* insert(
Node
*
root
,
int
key
) {
if
(
root
==
NIL
)
return
getNewNode(
key
);
if
(
root
->key ==
key
)
return
root
;
if
(
key
<
root
->key)
root
->lchild = insert(
root
->lchild,
key
);
else
root
->rchild = insert(
root
->rchild,
key
);
//重新计算当前节点高度
update_height(
root
);
//维护平衡
return
maintain(
root
);
}
Node
* predecessor(
Node
*
root
) {
Node
* temp =
root
->lchild;
while
(temp->rchild !=
NIL
) temp = temp->rchild;
return
temp;
}
Node
* erase(
Node
*
root
,
int
key
) {
if
(
root
==
NIL
)
return
root
;
if
(
key
<
root
->key)
root
->lchild = erase(
root
->lchild,
key
);
else
if
(
key
>
root
->key)
root
->rchild = erase(
root
->rchild,
key
);
else
{
//删除度为0,1的节点
if
(
root
->lchild ==
NIL
||
root
->rchild ==
NIL
) {
Node
* temp =
root
->lchild !=
NIL
?
root
->lchild :
root
->rchild;
free(
root
);
return
temp;
}
//删除度为2的节点
else
{
Node
* temp = predecessor(
root
);
root
->key = temp->key;
root
->lchild = erase(
root
->lchild, temp->key);
}
}
//重新计算当前节点高度
update_height(
root
);
//维护平衡
return
maintain(
root
);
}
Node
* find(
Node
*
root
,
int
key
) {
if
(
root
==
NIL
)
return
NIL
;
if
(
root
->key ==
key
)
return
root
;
if
(
key
<
root
->key)
return
find(
root
->lchild,
key
);
return
find(
root
->rchild,
key
);
}
void
clear(
Node
*
root
) {
if
(
root
==
NULL
)
return
;
clear(
root
->lchild);
clear(
root
->rchild);
free(
root
);
return
;
}
//前序遍历
void
output(
Node
*
root
) {
if
(
root
==
NIL
)
return
;
printf(
"(%d[%d] | %d, %d)\n"
,
K
(
root
),
H
(
root
),
K
(
L
(
root
)),
K
(
R
(
root
))
);
output(
root
->lchild);
output(
root
->rchild);
return
;
}
int
main() {
srand(time(0));
Node
* root =
NIL
;
int
x;
// insert
while
(~scanf_s(
"%d"
, &x)) {
if
(x == -1)
break
;
printf(
"insert %d to avl tree\n"
, x);
root = insert(root, x);
output(root);
}
// erase
while
(~scanf_s(
"%d"
, &x)) {
if
(x == -1)
break
;
printf(
"erase %d from avl tree\n"
, x);
root = erase(root, x);
output(root);
}
// find
while
(~scanf_s(
"%d"
, &x)) {
if
(x == -1)
break
;
printf(
"find %d in avl : %d\n"
, x, find(root, x) !=
NIL
);
}
return
0;
}
三,红黑树
插入操作
原则:
-
调整前后,每条路径黑色节点数不变。
-
对于颜色不确定的节点,其父节点一定是黑色。
-
插入到红黑树的节点一定为红色。
情况1:
调整方法:
将祖父节点调整成红色,叔父节点和父节点调整成黑色
情况2:
左边红色节点的左子树是红色,导致失衡--LL型
调整方式: 大右旋-->红色上浮/下沉(大右旋后的根节点及其左右子树改成了红黑黑/黑红红)
情况3:
左边红色节点的右子树是红色,导致失衡--LR型
调整方式: 小左旋 --> 大右旋-->红色上浮/下沉(大右旋后的根节点及其左右子树改成了红黑黑/黑红红)
情况4:
右边红色节点的右子树是红色,导致失衡--RR型
调整方式: 大左旋-->红色上浮/下沉(大左旋后的根节点及其左右子树改成了红黑黑/黑红红)
情况5:
右边红色节点的左子树是红色,导致失衡--RL型
调整方式: 小右旋 --> 大左旋-->红色上浮/下沉(大右旋后的根节点及其左右子树改成了红黑黑/黑红红)
红黑树的删除操作
1.删除度为零的红色节点:直接删除
2.删除度为1的红色节点:不存在度为1的红色节点,违背了红黑树的第五条性质(不同路径的黑色节点数相同);
3.删除度为1的黑色节点:其唯一子树不能存在黑色节点,修改方法:红提升,并变黑;
以上三种删除情况,不会造成红黑树失衡
4.删除度为0的黑色节点:将被删除的黑色节点的NIL节点设置成双重黑节点;
那么双重黑节点违反了红黑树的性质,引发红黑树的失衡,则
删除调整的操作主要是解决删除度为0的黑色节点而产生的双重黑节点
ps:删除度为2的节点可以转换成删除度为1的节点
删除调整情况:(x是双重黑节点)
1.双重黑节点的兄弟节点是黑色,并且双重黑色的兄弟节点的子节点都为黑色
-
调整方法: 给父节点加上一重黑,其左右子树减去一重黑。
43:黑/红->双重黑/黑 9:黑->红 95:双重黑->黑
2.双重黑的兄弟节点为黑色,并在右侧,其右子树(记为a)为红色(RR型失衡)
-
RR类型的判断优先级高于RL类型
-
调整方法:先抓着双重黑节点的父节点大左旋,再将双重黑节点的 兄弟节点的颜色变成原父节点的颜色,原父节点和a(旋转后的根节点的左右子节点)的颜色变成黑色,双重黑节点变成黑色。
3.双重黑的兄弟节点为黑色,并在左侧,其左子树(记为a)为红色(LL型失衡)
-
LL类型的判断优先级高于LR类型
-
调整方法:先抓着双重黑节点的父节点大右旋,再将双重黑节点的 兄弟节点的颜色变成原父节点的颜色,原父节点和a(旋转后的根节点的左右子节点)的颜色变成黑色,双重黑节点变成黑色。
4.双重黑的兄弟节点为黑色,并在右侧,其左子树(记为b)为红色,且右子树为黑色(RL型失衡)
-
调整方法:先抓着双重黑节点的兄弟节点小右旋,转换成RR型失衡
5.双重黑的兄弟节点为黑色,并在左侧,其右子树(记为b)为红色,且左子树为黑色(LR型失衡)
-
调整方法:先抓着双重黑节点的兄弟节点小左旋,转换成LL型失衡
6.双重黑节点的兄弟节点为红色,且位于右侧
-
调整方法:抓着双重黑节点的父节点大左旋,原根节点修改成红色,新根节点修改成黑色,再次构成情况1/2/3/4/5, 递归到左子树去处理;
蓝框表示节点颜色确定;
7.双重黑节点的兄弟节点为红色,且位于左侧
-
调整方法:抓着双重黑节点的父节点大右旋,原根节点修改成红色,新根节点修改成黑色,再次构成情况1/2/3/4/5, 递归到右子树去处理;
代码演示:
#include
<string>
#include
<vector>
#include
<iostream>
#include
<cinttypes>
#include
<iostream>
#include
<ctime>
#include
<cstdio>
using
namespace
std;
#define
RED
0
#define
BLACK
1
#define
DBLACK
2
#define
NIL
(&__NIL)
#define
K
(n) (n->key)
#define
L
(n) (n->lchild)
#define
R
(n) (n->rchild)
#define
C
(n) (n->color)
typedef
struct
Node
{
int
key, color;
// 0 red, 1 black, 2 double black;
struct
Node
*rchild, *lchild;
}
Node
;
Node
__NIL;
void
init_NIL() {
NIL
->key = -1;
NIL
->rchild =
NIL
->lchild =
NIL
;
NIL
->color =
BLACK
;
return
;
}
//为保证相同路径的黑色节点数目相同,新生成的节点为红色
Node
* getNewNode(
int
key
) {
Node
* p = (
Node
*)malloc(
sizeof
(
Node
));
p->key =
key
;
p->color =
RED
;
p->rchild = p->lchild =
NIL
;
return
p;
}
//判断左右子树是否有红色
bool
has_red_node(
Node
*
root
) {
return
root
->lchild->color ==
RED
||
root
->rchild->color ==
RED
;
}
//左旋
Node
* left_rotate(
Node
*
root
) {
Node
* new_root =
root
->rchild;
root
->rchild = new_root->lchild;
new_root->lchild =
root
;
return
new_root;
}
//右旋
Node
* right_rotate(
Node
*
root
) {
Node
* new_root =
root
->lchild;
root
->lchild = new_root->rchild;
new_root->rchild =
root
;
return
new_root;
}
//插入调整
Node
* insert_maintain(
Node
*
root
) {
int
flag = 0;
//判断祖父节点是否为LL/R型(情况2/3)
if
(
C
(
L
(
root
)) ==
RED
&& has_red_node(
L
(
root
))) flag = 1;
//判断祖父节点是否为RR/L型(情况4/5)
if
(
C
(
R
(
root
)) ==
RED
&& has_red_node(
R
(
root
))) flag = 2;
//没有出现红色节点的子节点也是红色的情况
if
(flag == 0)
return
root
;
//
if
(
C
(
L
(
root
)) ==
RED
&&
C
(
R
(
root
)) ==
RED
)
goto
red_up_maintain;
if
(flag == 1) {
//LR型判断
if
(
C
(
R
(
L
(
root
))) ==
RED
) {
//小左旋
L
(
root
) = left_rotate(
L
(
root
));
}
//大右旋
root
= right_rotate(
root
);
}
else
{
//RL型判断
if
(
C
(
L
(
R
(
root
))) ==
RED
) {
//小右旋
R
(
root
) = right_rotate(
R
(
root
));
}
//大左旋
root
= left_rotate(
root
);
}
red_up_maintain:
C
(
root
) =
RED
;
C
(
L
(
root
)) =
C
(
R
(
root
)) =
BLACK
;
return
root
;
}
//插入
Node
* __insert(
Node
*
root
,
int
key
) {
if
(
root
==
NIL
)
return
getNewNode(
key
);
if
(
root
->key ==
key
)
return
root
;
if
(
key
<
root
->key)
root
->lchild = __insert(
root
->lchild,
key
);
else
root
->rchild = __insert(
root
->rchild,
key
);
//插入调整
return
insert_maintain(
root
);
}
Node
* insert(
Node
*
root
,
int
key
) {
//封装插入功能;
root
= __insert(
root
,
key
);
//保证根节点是黑色
root
->color =
BLACK
;
return
root
;
}
//寻找根节点的前驱
Node
* predecessor(
Node
*
root
) {
Node
* temp =
root
->lchild;
while
(temp->rchild !=
NIL
)temp = temp->rchild;
return
temp;
}
Node
* erase_maintain(
Node
*
root
) {
if
(
C
(
L
(
root
)) !=
DBLACK
&&
C
(
R
(
root
)) !=
DBLACK
)
return
root
;
//双重黑节点的兄弟节点是红色
if
(has_red_node(
root
)) {
//原根节点变成红色
root
->color =
RED
;
//情况7
if
(
root
->lchild->color ==
RED
) {
root
= right_rotate(
root
);
//递归到右子树进行删除调整
root
->rchild = erase_maintain(
root
->rchild);
}
//情况6
else
{
root
= left_rotate(
root
);
//递归到左子树进行删除调整
root
->lchild = erase_maintain(
root
->lchild);
}
//原红色兄弟节点变成黑色
root
->color =
BLACK
;
return
root
;
}
if
((
root
->lchild->color ==
DBLACK
&& !has_red_node(
root
->rchild))
|| (
root
->rchild->color ==
DBLACK
&& !has_red_node(
root
->lchild))) {
root
->color += 1;
root
->lchild->color -= 1;
root
->rchild->color -= 1;
return
root
;
}
if
(
root
->rchild->color ==
DBLACK
) {
//双重黑节点变成黑色
root
->rchild->color =
BLACK
;
//LR型失衡
if
(
root
->lchild->lchild->color !=
RED
) {
root
->lchild = left_rotate(
root
->lchild);
}
//LL型失衡
root
->lchild->color =
root
->color;
root
= right_rotate(
root
);
}
else
{
//双重黑节点变成黑色
root
->lchild->color =
BLACK
;
//RL型失衡
if
(
root
->rchild->rchild->color !=
RED
) {
root
->rchild = right_rotate(
root
->rchild);
}
//LL型失衡
root
->rchild->color =
root
->color;
root
= left_rotate(
root
);
}
//旋转后的根节点的左右子节点的颜色变成黑色
root
->lchild->color =
root
->rchild->color =
BLACK
;
return
root
;
}
//删除操作
Node
* __erase(
Node
*
root
,
int
key
) {
if
(
root
==
NIL
)
return
root
;
if
(
key
<
root
->key) {
root
->lchild = __erase(
root
->lchild,
key
);
}
else
if
(
key
>
root
->key) {
root
->rchild = __erase(
root
->rchild,
key
);
}
else
{
//度为0/1的删除情况
if
(
root
->lchild ==
NIL
||
root
->rchild ==
NIL
) {
Node
* temp =
root
->lchild ==
NIL
?
root
->rchild :
root
->lchild;
temp->color +=
root
->color;
free(
root
);
return
temp;
}
//度为2的删除情况--转换为度为1/0的删除情况
Node
* temp = predecessor(
root
);
root
->key = temp->key;
root
->lchild = __erase(
root
->lchild, temp->key);
}
//删除调整
return
erase_maintain(
root
);
}
//封装删除操作
Node
* erase(
Node
*
root
,
int
key
) {
root
= __erase(
root
,
key
);
root
->color =
BLACK
;
return
root
;
}
void
clear(
Node
*
root
) {
if
(
root
==
NIL
)
return
;
clear(
root
->lchild);
clear(
root
->rchild);
free(
root
);
return
;
}
void
output(
Node
*
root
) {
if
(
root
==
NIL
)
return
;
printf(
"(%d| %d; %d, %d)\n"
,
C
(
root
),
K
(
root
),
K
(
L
(
root
)),
K
(
R
(
root
))
);
output(
root
->lchild);
output(
root
->rchild);
return
;
}
int
main() {
init_NIL();
srand(time(0));
#define
MAX_N
10
Node
* root =
NIL
;
for
(
int
i = 0; i <
MAX_N
; i++) {
int
x = rand() % 100;
printf(
"\ninsert %d to red black tree : \n"
, x);
root = insert(root, x);
output(root);
}
int
x;
while
(~scanf_s(
"%d"
, &x)) {
printf(
"\nerase %d from red black tree\n"
, x);
root = erase(root, x);
output(root);
}
return
0;
}
四,B-树
⼀棵 m 阶 B 树,需要满
⾜下列特性:
1. 树中每个节点,最多含有 m 棵
⼦树
2. 若
根节点不是叶
⼦节点,则
⾄少有 2 棵
⼦树
3. 除根结点之外的所有非终端结点
⾄少有⌈m/2⌉棵
⼦树 (⌈m/2⌉表示m/2向上取整)
4. 如果⼀个结点有n-1个关键字,则该结点有n个分支,且这n-1个关键字按照递增顺序排列
5. 每个结点的结构为:( n,A0,K1,A1,K2,A2,… ,Kn,An )
-
n:节点数量
-
A0 ~ An:分支
-
K1~Kn:节点
-
节点分支的关系: 例如:A0< K1, K1 < A1 < K2, K2 < A2 < K3 ..... An > Kn
6. 非根结点中关键字的个数 n,满
⾜
:⌈m/2⌉-1 ≤ n ≤ m-1 -->平衡条件关键
7. 所有叶
⼦节点处在同⼀层
m 阶 B 树的性质解读:
1. B 树中只有根节点没办法满⾜拥有⾄少 ⌈m/2⌉ 棵⼦树的条件,其他节点均能满⾜
2. B 树是⼀种
⾼度平衡的树形结构,比 AVL 树结构上更优美
插入操作:
证明:节点分裂的合理性
非根结点中关键字的个数 n,满
⾜:⌈m/2⌉-1 ≤ n ≤ m-1
当m = 2n + 1
⌈m/2⌉-1 = n;
分裂后:
左子树节点数:(m - 1) / 2 = n
右子树节点数:(m - 1) / 2 = n
当m = 2n
⌈m/2⌉-1 = n - 1;
分裂后:
左子树节点数:(m - 1 - 1) / 2 = n - 1
右子树节点数:(m - 1 + 1) / 2 = n
左右节点数均符合要求
删除操作:
m 阶 B 树的元素删除:
1. 终端节点直接删除
2. 非终端节点,与(前驱/后继)交换,再删除
代码演示:
#include
<iostream>
#include
<string>
#include
<cstring>
#include
<cstdlib>
#include
<ctime>
#include
<cstdio>
using
namespace
std;
#define
MAX_M
5
#define
MAX_OP
15
typedef
struct
Node
{
//节点数量
int
n;
//节点值
int
key[
MAX_M
+ 1];
//分支
struct
Node
* next[
MAX_M
+ 1];
}
Node
;
Node
* getNewNode() {
Node
* p = (
Node
*)malloc(
sizeof
(
Node
));
p->n = 0;
//分支数组初始化为NULL
memset(p->next, 0,
sizeof
(
Node
*) * (
MAX_M
+ 1));
return
p;
}
//插入操作
//插入调整
Node
* insert_maintain(
Node
*
root
,
Node
*
child
,
int
pos
) {
//关键值数没有超过MAX_M
if
(
child
->n <
MAX_M
)
return
root
;
//要提取的关键值位置
int
spos =
MAX_M
/ 2;
//分裂成的两个小节点
Node
* node1 = getNewNode();
Node
* node2 = getNewNode();
node1->n = spos;
node2->n =
MAX_M
- 1 - spos;
//node1的赋值
for
(
int
i = 0; i < spos; i++) {
node1->key[i] =
child
->key[i];
node1->next[i] =
child
->next[i];
}
node1->next[spos] =
child
->next[spos];
//node2的赋值
for
(
int
i = 0; i < node2->n; i++) {
node2->key[i] =
child
->key[i + spos + 1];
node2->next[i] =
child
->next[i + spos + 1];
}
node2->next[node2->n] =
child
->next[
child
->n];
//i = root->n 简化了代码
for
(
int
i =
root
->n; i >=
pos
; i--) {
root
->key[i + 1] =
root
->key[i];
root
->next[i + 1] =
root
->next[i];
}
root
->key[
pos
] =
child
->key[spos];
root
->next[
pos
] = node1;
root
->next[
pos
+ 1] = node2;
root
->n += 1;
free(
child
);
return
root
;
}
Node
* insert_key(
Node
*
root
,
int
key
) {
//根节点为空
if
(
root
==
NULL
) {
root
= getNewNode();
root
->key[(
root
->n)++] =
key
;
return
root
;
}
//插入终端节点
int
pos = 0;
//查找要插入的位置
while
(pos <
root
->n &&
root
->key[pos] <
key
) pos += 1;
if
(pos <
root
->n &&
root
->key[pos] ==
key
)
return
root
;
for
(
int
i =
root
->n - 1; i >= pos; i--) {
root
->key[i + 1] =
root
->key[i];
}
root
->key[pos] =
key
;
root
->n += 1;
return
root
;
}
Node
* __insert(
Node
*
root
,
int
key
) {
// 根节点为空 || 当前节点为终端节点
if
(
root
==
NULL
||
root
->next[0] ==
NULL
) {
return
insert_key(
root
,
key
);
}
int
pos = 0;
while
(pos <
root
->n &&
root
->key[pos] <
key
) pos += 1;
//判断key是否已经存在
if
(pos <
root
->n &&
root
->key[pos] ==
key
)
return
root
;
//向next[pos]分支遍历
__insert(
root
->next[pos],
key
);
return
insert_maintain(
root
,
root
->next[pos], pos);
}
Node
* insert(
Node
*
root
,
int
key
) {
root
= __insert(
root
,
key
);
//因为插入调整从父节点往下看
//所以当根节点满了,要单独调整
if
(
root
->n ==
MAX_M
) {
//生成空的新根节点
Node
* p = getNewNode();
p->next[0] =
root
;
root
= insert_maintain(p,
root
, 0);
}
return
root
;
}
void
clear(
Node
*
root
) {
if
(
root
==
NULL
)
return
;
for
(
int
i = 0; i <=
root
->n; i++) {
clear(
root
->next[i]);
}
free(
root
);
return
;
}
void
print_node(
Node
*
root
) {
printf(
"%d : "
,
root
->n);
for
(
int
i = 0; i <
root
->n; i++) {
printf(
"%4d"
,
root
->key[i]);
}
printf(
" | "
);
if
(
root
->next[0] ==
NULL
)
goto
output_end;
for
(
int
i = 0; i <=
root
->n; i++) {
printf(
"%4d"
,
root
->next[i]->key[0]);
}
output_end:
printf(
"\n"
);
return
;
}
void
output(
Node
*
root
) {
if
(
root
==
NULL
)
return
;
print_node(
root
);
for
(
int
i = 0; i <=
root
->n; i++) {
output(
root
->next[i]);
}
return
;
}
int
main() {
srand(time(0));
Node
* root =
NULL
;
for
(
int
i = 0; i <
MAX_OP
; i++) {
int
val = rand() % 100;
root = insert(root, val);
printf(
"\ninsert %d to BTree : \n"
, val);
output(root);
}
return
0;
}
左旋/右旋:
左子树富裕--右旋,右子树富裕--左旋,
合并:
代码演示:
#include
<iostream>
#include
<string>
#include
<cstring>
#include
<cstdlib>
#include
<ctime>
#include
<cstdio>
using
namespace
std;
#define
MAX_M
3
#define
MAX_OP
12
#define
LCHILD
(root, pos) (root->next[pos])
#define
RCHILD
(root, pos) (root->next[pos + 1])
#define
LAST_KEY
(root) (root->key[root->n - 1])
#define
LAST_CHILD
(root) (root->next[root->n])
typedef
struct
Node
{
//关键字数量
int
n;
//关键字值
int
key[
MAX_M
+ 1];
//分支
struct
Node
* next[
MAX_M
+ 1];
}
Node
;
Node
* getNewNode() {
Node
* p = (
Node
*)malloc(
sizeof
(
Node
));
p->n = 0;
//分支数组初始化为NULL
memset(p->next, 0,
sizeof
(
Node
*) * (
MAX_M
+ 1));
return
p;
}
//插入操作
//插入调整
Node
* insert_maintain(
Node
*
root
,
Node
*
child
,
int
pos
) {
//关键值数没有超过MAX_M
if
(
child
->n <
MAX_M
)
return
root
;
//要提取的关键值位置
int
spos =
MAX_M
/ 2;
//分裂成的两个小节点
Node
* node1 = getNewNode();
Node
* node2 = getNewNode();
node1->n = spos;
node2->n =
MAX_M
- 1 - spos;
//node1的赋值
for
(
int
i = 0; i < spos; i++) {
node1->key[i] =
child
->key[i];
node1->next[i] =
child
->next[i];
}
node1->next[spos] =
child
->next[spos];
//node2的赋值
for
(
int
i = 0; i < node2->n; i++) {
node2->key[i] =
child
->key[i + spos + 1];
node2->next[i] =
child
->next[i + spos + 1];
}
node2->next[node2->n] =
child
->next[
child
->n];
//i = root->n 简化了代码
for
(
int
i =
root
->n; i >=
pos
; i--) {
root
->key[i + 1] =
root
->key[i];
root
->next[i + 1] =
root
->next[i];
}
root
->key[
pos
] =
child
->key[spos];
root
->next[
pos
] = node1;
root
->next[
pos
+ 1] = node2;
root
->n += 1;
free(
child
);
return
root
;
}
Node
* insert_key(
Node
*
root
,
int
key
) {
//根节点为空
if
(
root
==
NULL
) {
root
= getNewNode();
root
->key[(
root
->n)++] =
key
;
return
root
;
}
//插入终端节点
int
pos = 0;
//查找要插入的位置
while
(pos <
root
->n &&
root
->key[pos] <
key
) pos += 1;
if
(pos <
root
->n &&
root
->key[pos] ==
key
)
return
root
;
for
(
int
i =
root
->n - 1; i >= pos; i--) {
root
->key[i + 1] =
root
->key[i];
}
root
->key[pos] =
key
;
root
->n += 1;
return
root
;
}
Node
* __insert(
Node
*
root
,
int
key
) {
// 根节点为空 || 当前节点为终端节点
if
(
root
==
NULL
||
root
->next[0] ==
NULL
) {
return
insert_key(
root
,
key
);
}
int
pos = 0;
while
(pos <
root
->n &&
root
->key[pos] <
key
) pos += 1;
//判断key是否已经存在
if
(pos <
root
->n &&
root
->key[pos] ==
key
)
return
root
;
//向next[pos]分支遍历
__insert(
root
->next[pos],
key
);
return
insert_maintain(
root
,
root
->next[pos], pos);
}
Node
* insert(
Node
*
root
,
int
key
) {
root
= __insert(
root
,
key
);
//因为插入调整从父节点往下看
//所以当根节点满了,要单独调整
if
(
root
->n ==
MAX_M
) {
//生成空的新根节点
Node
* p = getNewNode();
p->next[0] =
root
;
root
= insert_maintain(p,
root
, 0);
}
return
root
;
}
//删除操作
void
erase_pos(
Node
*
root
,
int
pos
) {
for
(
int
i =
pos
+ 1; i <
root
->n; i++) {
root
->key[i - 1] =
root
->key[i];
}
root
->n -= 1;
return
;
}
//删除调整
//右旋
void
right_rotate(
Node
*
root
,
int
pos
) {
for
(
int
i =
RCHILD
(
root
,
pos
)->n + 1; i > 0; i--) {
RCHILD
(
root
,
pos
)->key[i] =
RCHILD
(
root
,
pos
)->key[i - 1];
RCHILD
(
root
,
pos
)->next[i] =
RCHILD
(
root
,
pos
)->next[i - 1];
}
RCHILD
(
root
,
pos
)->key[0] =
root
->key[
pos
];
root
->key[
pos
] =
LAST_KEY
(
LCHILD
(
root
,
pos
));
RCHILD
(
root
,
pos
)->next[0] =
LAST_CHILD
(
LCHILD
(
root
,
pos
));
LAST_CHILD
(
LCHILD
(
root
,
pos
)) =
NULL
;
RCHILD
(
root
,
pos
)->n += 1;
LCHILD
(
root
,
pos
)->n -= 1;
return
;
}
//左旋
void
left_rotate(
Node
*
root
,
int
pos
) {
LCHILD
(
root
,
pos
)->key[
LCHILD
(
root
,
pos
)->n] =
root
->key[
pos
];
LCHILD
(
root
,
pos
)->n += 1;
root
->key[
pos
] =
RCHILD
(
root
,
pos
)->key[0];
LAST_CHILD
(
LCHILD
(
root
,
pos
)) =
RCHILD
(
root
,
pos
)->next[0];
for
(
int
i = 0; i <
RCHILD
(
root
,
pos
)->n; i++) {
RCHILD
(
root
,
pos
)->key[i] =
RCHILD
(
root
,
pos
)->key[i + 1];
RCHILD
(
root
,
pos
)->next[i] =
RCHILD
(
root
,
pos
)->next[i + 1];
}
LAST_CHILD
(
RCHILD
(
root
,
pos
)) =
NULL
;
RCHILD
(
root
,
pos
)->n -= 1;
return
;
}
void
merge_node(
Node
*
root
,
int
pos
) {
Node
* node = getNewNode();
//拷贝pos左分支
for
(
int
i = 0; i <=
LCHILD
(
root
,
pos
)->n; i++) {
node->key[i] =
LCHILD
(
root
,
pos
)->key[i];
node->next[i] =
LCHILD
(
root
,
pos
)->next[i];
}
//拷贝root->key[pos]
node->n =
LCHILD
(
root
,
pos
)->n + 1;
node->key[node->n - 1] =
root
->key[
pos
];
//拷贝pos右分支
for
(
int
i = 0; i <=
RCHILD
(
root
,
pos
)->n; i++) {
node->key[i + node->n] =
RCHILD
(
root
,
pos
)->key[i];
node->next[i + node->n] =
RCHILD
(
root
,
pos
)->next[i];
}
node->n +=
RCHILD
(
root
,
pos
)->n;
free(
LCHILD
(
root
,
pos
));
free(
RCHILD
(
root
,
pos
));
for
(
int
i =
pos
+ 1; i <=
root
->n; i++) {
root
->key[i - 1] =
root
->key[i];
root
->next[i - 1] =
root
->next[i];
}
root
->next[
pos
] = node;
root
->n -= 1;
return
;
}
Node
* erase_maintain(
Node
*
root
,
int
pos
) {
//最少关键字数
int
lower_bound = (
MAX_M
+ 1) / 2 - 1;
if
(
root
->next[
pos
]->n >= lower_bound)
return
root
;
// root->next[pos]左边关键字富裕
if
(
pos
> 0 &&
root
->next[
pos
- 1]->n > lower_bound) {
//拎着pos - 1节点右旋
right_rotate(
root
,
pos
- 1);
}
// root->next[pos]右边关键字富裕
else
if
(
pos
<
root
->n &&
root
->next[
pos
+ 1]->n > lower_bound) {
拎着pos节点左旋
left_rotate(
root
,
pos
);
}
// root->next[pos]左右两边关键字都不富裕
else
{
//pos > 0:向前合并
if
(
pos
> 0) merge_node(
root
,
pos
- 1);
// merge(i, j) -> (j, j + 1)
//pos == 0 :向后合并
else
merge_node(
root
,
pos
);
}
return
root
;
}
Node
* __erase(
Node
*
root
,
int
key
) {
if
(
root
==
NULL
)
return
root
;
int
pos = 0;
//找到大于或等于key的关键字的位置
while
(pos <
root
->n &&
root
->key[pos] <
key
) pos += 1;
//当前节点为终端节点
if
(
root
->next[0] ==
NULL
) {
if
(
root
->key[pos] ==
key
) erase_pos(
root
, pos);
return
root
;
}
else
{
//找到key, 但不位于终端节点
if
(pos <
root
->n &&
root
->key[pos] ==
key
) {
//查找key所在位置的前驱
//前驱位于终端节点
Node
* temp =
root
->next[pos];
while
(temp->next[temp->n]) temp = temp->next[temp->n];
int
val = temp->key[temp->n - 1];
//前驱与要删除位置交换-->把要删除的节点移到终端节点
swap(
root
->key[pos], temp->key[temp->n - 1]);
}
//递归到终端节点删除key
root
->next[pos] = __erase(
root
->next[pos],
key
);
}
//pos为已删除关键字的分支
return
erase_maintain(
root
, pos);
}
Node
* erase(
Node
*
root
,
int
key
) {
root
= __erase(
root
,
key
);
//root的关键字数为0,将根节点的唯一子树作为新数根节点
if
(
root
->n == 0) {
Node
* temp =
root
->next[0];
free(
root
);
root
= temp;
}
return
root
;
}
void
clear(
Node
*
root
) {
if
(
root
==
NULL
)
return
;
for
(
int
i = 0; i <=
root
->n; i++) {
clear(
root
->next[i]);
}
free(
root
);
return
;
}
void
print_node(
Node
*
root
) {
printf(
"%d : "
,
root
->n);
for
(
int
i = 0; i <
root
->n; i++) {
printf(
"%4d"
,
root
->key[i]);
}
printf(
" | "
);
if
(
root
->next[0] ==
NULL
)
goto
output_end;
for
(
int
i = 0; i <=
root
->n; i++) {
printf(
"%4d"
,
root
->next[i]->key[0]);
}
output_end:
printf(
"\n"
);
return
;
}
void
output(
Node
*
root
) {
if
(
root
==
NULL
)
return
;
print_node(
root
);
for
(
int
i = 0; i <=
root
->n; i++) {
output(
root
->next[i]);
}
return
;
}
int
main() {
srand(time(0));
Node
* root =
NULL
;
for
(
int
i = 0; i <
MAX_OP
; i++) {
int
val = rand() % 100;
root = insert(root, val);
printf(
"\ninsert %d to BTree : \n"
, val);
output(root);
}
int
x;
while
(~scanf_s(
"%d"
, &x)) {
printf(
"erase %d from BTree : \n"
, x);
root = erase(root, x);
output(root);
}
return
0;
}