2024-03-19 02:45:09 +08:00

186 lines
5.7 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#define M 3
typedef struct tree *prt_tree;
struct tree
{
int data; //存储的数据
prt_tree left; //左子节点
prt_tree right; //右子节点
prt_tree brother; //兄弟节点
};
prt_tree create_node(int data)
{
prt_tree tree = malloc(sizeof(struct tree));
memset(tree, 0, sizeof(struct tree));
tree->data = data;
return tree;
}
prt_tree insert(int data, prt_tree root, prt_tree father)
{
if (root == NULL)
{
root = create_node(data);
return root;
}
//在兄弟节点进行搜索,直到data夹在两个兄弟节点之中,或者相等,或者为空
//如果相等不进行处理,直接返回
//如果比最小的还小,插入节点后,与第一个交换返回
//如果是夹在兄弟中,就进入第一个的右,或者第二个左节点
//如果等于NULL的话,证明这是叶子节点,就直接在中间插入,否则进行插入操作,回到第一行
//如果是空就插入在最后一个兄弟节点
//插入之后继续进行循环,得到n来判断这个节点数量有没有大于m
prt_tree tmp = root;
int n = 0;
while (tmp != NULL)
{
n += 1;
if (data == tmp->data)
{
//相等的情况
break;
}
else if (data < tmp->data)
{
//比最小还小的情况(也就是最小),往左边插入,先判断left节点是不是NULL
//为NULL则认为是叶子节点,数量+1,然后跳出循环,新节点变为老节点
//否则递归调用insert,往left节点继续搜索
if (tmp->left == NULL)
{
prt_tree new_tree = create_node(data);
new_tree->brother = tmp;
n += 1;
root = new_tree;
break;
}
else
{
//往左节点继续搜索
insert(data, tmp->left, tmp);
}
}
else if (tmp->brother == NULL)
{
//等于空的情况(也就是最大的情况),往右插入,先判断right节点是不是NULL
//为NULL则认为是叶子节点,新节点加入兄弟节点后,tmp指向兄弟节点,跳出循环
//否则递归调用insert,往right节点继续搜索
if (tmp->right == NULL)
{
prt_tree new_tree = create_node(data);
tmp->brother = new_tree;
tmp = tmp->brother;
break;
}
else
{
insert(data, tmp->right, tmp);
}
}
else if (data > tmp->data && data < tmp->brother->data)
{
//夹在中间的情况,如果right为空的就认为是叶子节点,插入在中间
if (tmp->right == NULL)
{
//插入在中间,新建立一个新的节点,然后将节点插入到中间
prt_tree new_tree = create_node(data);
prt_tree tmpPrtTree = tmp->brother;
tmp->brother = new_tree;
new_tree->brother = tmpPrtTree;
tmp = tmp->brother;
break;
}
else
{
//往父的right插入
insert(data, tmp->right, tmp);
}
}
tmp = tmp->brother;
}
//接着tmp继续循环,遍历这个节点有没有超过m
while (tmp != NULL)
{
tmp = tmp->brother;
n += 1;
}
//判断是否超过M
if (n > M)
{
//超过m,取出中间的前一个节点
prt_tree mid_before_tree = root;
prt_tree mid_tree = NULL;
int sub = ceil(M / 2);
for (int i = 0; i < sub; i++)
{
mid_before_tree = mid_before_tree->brother;
}
mid_tree = mid_before_tree->brother;
//取出中间的后,判断父节点,是不是等于当前,如果是等于当前root节点
//将这一整个块从mid_tree分开,中间节点提取到上一节点
mid_before_tree->brother = NULL;
mid_tree->left = root;
mid_tree->right = mid_tree->brother;
mid_tree->brother = NULL;
//则认为这是在操作根节点,操作的是根节点的话
//就要将现在的这个节点变为根节点
if (root == father)
{
root = mid_tree;
}
else
{
//然后判断比父节点大还是小
//比父大就是直接插入到父的兄弟节点
//然后父的兄弟的left为空
//比父小就进行交换,插入
//父right为空
if (father->data > data)
{
prt_tree tmp_node = father->brother;
father->brother = mid_tree;
mid_tree->brother = tmp_node;
}
else
{
//连接兄弟节点
mid_tree->brother = father->brother;
father->brother = mid_tree;
}
}
}
printf("data:%d\tn:%d\n", data, n);
return root;
}
//排序输出
void print_tree(prt_tree root)
{
if (root == NULL)
return;
print_tree(root->left);
printf("%d\t", root->data);
print_tree(root->brother);
if (root->brother == NULL)
{
print_tree(root->right);
}
}
int main()
{
prt_tree root = NULL;
root = insert(1, root, root);
root = insert(6, root, root);
root = insert(8, root, root);
root = insert(11, root, root);
root = insert(15, root, root);
root = insert(16, root, root);
root = insert(18, root, root);
print_tree(root);
return 0;
}