您的位置:首页 > 理论基础 > 数据结构算法

数据结构-各类树

2017-12-30 18:42 183 查看
  树中最基本的是二叉树,其中左边结点是左子树,右边结点是右子树。在二叉树的基础上再加上左子树小于根结点,右子树大于根节点这个约束的话,就成了二叉查找树。一颗好的二叉查找树可以在O(lgn)里完成查找。

  对于查找树的操作,主要时删除操作比较麻烦,删除时需考虑3种情况,

删除的是叶子节点(直接删即可)。

删除的节点有一边有子树(将删除结点的子树接到删除结点的父节点即可)

删除结点有两个子树(有多种处理方法,但实际原理都一样,就是找出大小最接近删除结点的结点来替换它,可以往左也可往右找,比如往右找的话,就得在右子树中找最小的那个,也就是从右子树的中序遍历的第一个)。

下面是二叉树一些基本操作的demo:

typedef struct treeNode {
void *key;
struct treeNode *parent;
struct treeNode *left;
struct treeNode *right;
}treeNode;

typedef struct bsTree {
int(*cmp)(const void *, const void *);
struct treeNode *root;
}bsTree,tree;

//cmp_int和print_key用于方便以后更改key类型的函数指针
int cmp_int(const void *p1, const void *p2) {
const int *pa = (int *)p1;
const int *pb = (int *)p2;
if (*pa < *pb)
return -1;
if (*pa == *pb)
return 0;
return 1;
}

void print_key(const void *key) {
const int *p = (int *)key;
printf("%d ", *p);
}

void treeNode_init(struct treeNode *p, void *key) {
p->key = key;
p->left = NULL;
p->right = NULL;
p->parent = NULL;
}

bsTree *tree_create(int(*cmp)(const void *, const void *)) {
bsTree *t = (bsTree *)malloc(sizeof(bsTree));
t->cmp = cmp;
t->root = NULL;
return t;
}

int insert_node(bsTree *t, struct treeNode *in) {
struct treeNode *y = NULL, *x = t->root;
//y指向插入结点的父节点
while (x != NULL) {
y = x;
if (t->cmp(in->key, x->key) < 0) {
x = x->left;
}
else {
x = x->right;
}
}
in->parent = y;
if (y == NULL) {
t->root = in;
}
else {
if (t->cmp(in->key, y->key) < 0) {
y->left = in;
}
else {
y->right = in;
}
}
return 1;
}

int delete_node(bsTree *t, struct treeNode *del)
{
struct treeNode *x, *y;
//删除的节点有3种情况
if (del == NULL) {
printf("该节点不存在\n");
return -1;
}
if ( del->right == NULL) {
del->parent->left = del->left;
if (del->left != NULL) {
del->left->parent = del->parent;
}
free(del);
}
else {
y = del;
4000
//x用以指向最终和del替换的结点
//y用以判断del的右子树是否还有左子树
x = del->right;   //有两个情况需要知道,del的右结点是否有左子树, 若有,那么将最左子树的右子树接到它的父节点的左边
while (x->left != NULL) {
y = x;         //y指针变化则有左子树
x = x->left;
}
del->key = x->key;  //替换待删除结点,最后再释放x
if (y != del) {
y->left = x->right;//有左子树的话需对左子树的右子树处理
x->right->parent = y;
}
else {
y->right = x->right;
x->right->parent = y;
}
free(x);
}
return 0;
}

//递归中序遍历,参数为开始访问的节点和访问其中节点的处理函数。
void midorder(struct treeNode *x, void (*handle)(const void *)) {
if (x != NULL) {
midorder(x->left, handle);
handle(x->key);
midorder(x->right, handle);
}
}

void preorder(struct treeNode *x, void (*handle)(const void *)) {
if (x != NULL) {
handle(x->key);
preorder(x->left, handle);
preorder(x->right, handle);
}
}

void postorder(struct treeNode *x, void (*handle)(const void *)) {
if (x != NULL) {
preorder(x->left, handle);
preorder(x->right, handle);
handle(x->key);
}
}

int main() {
tree *t = tree_create(cmp_int);

for (int i = 0; i < 10; i++) {
struct treeNode *node = (treeNode *)malloc(sizeof(treeNode));
int *p = (int *)malloc(sizeof(int));
*p = i;
treeNode_init(node, p);
insert_node(t, node);
}

printf("中序遍历:\n");
midorder(t->root, print_key);
return 0;
}


  二叉树只是具有查找的性质,但是很容易出现树变形,比如极端情况下全是右子树或是左子树的话,就变成一个链表了,加速查找的意义也没有了,所以二叉树需要一些维护,使其保持树的良好特性。

  对于维持树平衡也有很多方法,各有特点,其中最基本的操作是旋转,通过旋转使偏移的树结构恢复。SBT的话有它自己的一个特别操作。

  其中红黑树的效率比较高,但是编程复杂度也比较高,下面是算法导论中红黑树的demo:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct red_black_tree_type *tree;

enum color_enum{
color_red,
color_black
};
struct tree_node{
void*key;
enum color_enum color;
struct tree_node *parent;
struct tree_node *left;
struct tree_node *right;
};

struct red_black_tree_type{
int(*comp)(const void*, const void*);
struct tree_node *root;
struct tree_node *nil;
};

void tree_node_ini(struct tree_node *p, void* key)
{
p->key = key;
p->parent = NULL;
p->left = NULL;
p->right = NULL;
p->color = color_black;
}

void tree_left_rotate(tree t, struct tree_node *x)
{
struct tree_node *y = x->right;
x->right = y->left;
if (y->left != t->nil) {
y->left->parent = x;
}
y->parent = x->parent;
if (x->parent == t->nil) {
t->root = y;
}
else {
if (x == x->parent->left) {
x->parent->left = y;
}
else {
x->parent->right = y;
}
}
y->left = x;
x->parent = y;
}

void tree_right_rotate(tree t, struct tree_node *x)
{
struct tree_node *y = x->left;
x->left = y->right;
if (y->right != t->nil) {
y->right->parent = x;
}
y->parent = x->parent;
if (x->parent == t->nil) {
t->root = y;
}
else {
if (x == x->parent->left) {
x->parent->left = y;
}
else {
x->parent->right = y;
}
}
y->right = x;
x->parent = y;
}

tree tree_create(int(*comp)(const void*, const void*))
{
tree t = (tree )malloc(sizeof(struct red_black_tree_type));
t->comp = comp;
t->nil = (tree_node *)malloc(sizeof(struct tree_node));
tree_node_ini(t->nil, NULL);
t->root = t->nil;
return t;
}

void tree_destroy_all_node(tree t, struct tree_node *x,
void(*free_key)(void*))
{
if (x != t->nil) {
tree_destroy_all_node(t, x->left, free_key);
tree_destroy_all_node(t, x->right, free_key);
free_key(x->key);
free(x);
}
}

void tree_destroy(tree t, void(*free_key)(void*))
{
tree_destroy_all_node(t, t->root, free_key);
free(t->nil);
free(t);
}

void tree_inorder_walk(tree t, struct tree_node*x,
void(*handle)(const void*))
{
if (x != t->nil) {
tree_inorder_walk(t, x->left, handle);
handle(x->key);
printf("");
tree_inorder_walk(t, x->right, handle);
}
}

struct tree_node*tree_search(tree t, struct tree_node *x, void*key)
{
if (x == t->nil || t->comp(key, x->key) == 0) {
return x;
}
if (t->comp(key, x->key)<0) {
return tree_search(t, x->left, key);
}
else {
return tree_search(t, x->right, key);
}
}
void tree_count_leaf(tree t, struct tree_node *x,
struct tree_node *leaf_array[], int*num)
{
if (x != t->nil) {
if (x->left == t->nil&&x->right == t->nil) {
leaf_array[++*num] = x;
}
tree_count_leaf(t, x->left, leaf_array, num);
tree_count_leaf(t, x->right, leaf_array, num);
}
}

void tree_black_height(tree t, struct tree_node *x,
struct tree_node *leaf_node,
int*black_height)
{
if (x->color == color_black) {
++*black_height;
}
if (x == t->nil) {
return;
}
if (t->comp(leaf_node->key, x->key)<0) {
tree_black_height(t, x->left, leaf_node, black_height);
}
else {
tree_black_height(t, x->right, leaf_node, black_height);
}
}

struct tree_node *tree_minimum(tree t, struct tree_node *x)
{
while (x != t->nil&&x->left != t->nil) {
x = x->left;
}
return x;
}

struct tree_node *tree_successor(tree t, struct tree_node *x)
{
if (x->right != t->nil) {
return tree_minimum(t, x->right);
}
struct tree_node *y = x->parent;
while (y != t->nil&&x == y->right) {
x = y;
y = y->parent;
}
return y;
}

void tree_insert_fixup(tree t, struct tree_node *z)
{
struct tree_node *y = t->nil;
while (z->parent->color == color_red) {
if (z->parent == z->parent->parent->left) {
y = z->parent->parent->right;
//      情况1:z  的叔叔  y 是红色的
if (y->color == color_red) {
z->parent->color = color_black;
y->color = color_black;
z->parent->parent->color = color_red;
z = z->parent->parent;
}
else {
//情况2:z的叔叔y是黑色的,z是右孩子
if (z == z->parent->right) {
z = z->parent;
tree_left_rotate(t, z);
}
//情况3:z的叔叔y是黑色的,z是左孩子
z->parent->color = color_black;
z->parent->parent->color = color_red;
tree_right_rotate(t, z->parent->parent);
}
}
else {
y = z->parent->parent->left;
if (y->color == color_red) {
z->parent->color = color_black;
y->color = color_black;
z->parent->parent->color = color_red;
z = z->parent->parent;
}
else {
if (z == z->parent->left) {
z = z->parent;
tree_right_rotate(t, z);
}
z->parent->color = color_black;
z->parent->parent->color = color_red;
tree_left_rotate(t, z->parent->parent);
}
}
}
t->root->color = color_black;
}

void tree_insert(tree t, struct tree_node *z)
{
struct tree_node *y = t->nil;
struct tree_node *x = t->root;
while (x != t->nil) {
y = x;
if (t->comp(z->key, x->key)<0) {
x = x->left;
}
else {
x = x->right;
}
}
z->parent = y;
if (y == t->nil) {
t->root = z;
}
else {
if (t->comp(z->key, y->key)<0) {
y->left = z;
}
else {
y->right = z;
}
}
z->left = t->nil;
z->right = t->nil;
z->color = color_red;
tree_insert_fixup(t, z);
}

void tree_delete_fixup(tree t, struct tree_node *x)
{
struct tree_node *w = t->nil;
while (x != t->root&&x->color == color_black) {
if (x == x->parent->left) {
w = x->parent->right;
//情况1:x的兄弟w是红色的
if (w->color == color_red) {
w->color = color_black;
x->parent->color = color_red;
tree_left_rotate(t, x->parent);
w = x->parent->right;
}
else {
//情况2:x的兄弟w是黑色的,而且w的两个孩子都是黑色的
if (w->left->color == color_black
&&w->right->color == color_black) {
w->color = color_red;
x = x->parent;
}

d11b
else {
//情况3:x的兄弟w是黑色的,w的左孩子是红的,右孩子是
//黑的
if (w->right->color == color_black) {
w->left->color = color_black;
w->color = color_red;
tree_right_rotate(t, w);
w = x->parent->right;
}
//     4:x         w           ,     w
//情况  的兄弟 是黑色的而且 的右孩子是红色的
w->color = x->parent->color;
x->parent->color = color_black;
w->right->color = color_black;
tree_left_rotate(t, x->parent);
x = t->root;
}
}
}
else {
w = x->parent->left;
if (w->color == color_red) {
w->color = color_black;
x->parent->color = color_red;
tree_right_rotate(t, x->parent);
w = x->parent->left;
}
else {
if (w->right->color == color_black
&&w->left->color == color_black) {
w->color = color_red;
x = x->parent;
}
else {
if (w->left->color == color_black) {
w->right->color = color_black;
w->color = color_red;
tree_left_rotate(t, w);
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = color_black;
w->left->color = color_black;
tree_right_rotate(t, x->parent);
x = t->root;
}
}
}
}
x->color = color_black;
}

void swap(void*a, void*b, size_t elem_size)
{
if (a == NULL || b == NULL || a == b)
return;
char *temp = (char *)malloc(elem_size);                 /*vs不支持c99变长数组*/
memcpy(temp, a, elem_size);
memcpy(a, b, elem_size);
memcpy(b, temp, elem_size);
}

struct tree_node *tree_delete(tree t, struct tree_node *z)
{
struct tree_node *y;
struct tree_node *x;
if (z->left == t->nil || z->right == t->nil) {
y = z;
}
else {
y = tree_successor(t, z);
}
if (y->left != t->nil) {
x = y->left;
}
else {
x = y->right;
}
x->parent = y->parent;
if (y->parent == t->nil) {
t->root = x;
}
else {
if (y == y->parent->left) {
y->parent->left = x;
}
else {
y->parent->right = x;
}
}
if (y != z) {
/*要删除的结点y是z的后继,交换z和y结点的内容*/
swap(&z->key, &y->key, sizeof(void*));
}
if (y->color == color_black) {
tree_delete_fixup(t, x);
}
return y;
}

int cmp_int(const void *p1, const void *p2)
{
const int *pa = (int *)p1;
const int *pb = (int *)p2;
if (*pa<*pb)
return-1;
if (*pa == *pb)
return 0;
return 1;
}
void print_key(const void *key)
{
const int *p = (int *)key;
printf("%-2d", *p);
}

int main()
{
tree t = tree_create(cmp_int);
for (int i = 0; i<10; i++) {
struct tree_node *node = (tree_node *)malloc(sizeof(struct tree_node));
int*ip = (int *)malloc(sizeof(int));
*ip = i;
tree_node_ini(node, ip);
tree_insert(t, node);
}
printf("中序遍历结果:\n");
tree_inorder_walk(t, t->root, print_key);
printf("\n");
int k = 2;
struct tree_node *result = tree_search(t, t->root, &k);
printf("查找关键字:%d的结果:%s\n", k,
result != t->nil ? "成功" : "失败");
struct tree_node *del_node = tree_delete(t, result);
free(del_node->key);
free(del_node);
result = tree_search(t, t->root, &k);
printf("删除关键字:%d的结果:%s\n", k,
result == t->nil ? "成功" : "失败");
printf("查看黑高度:\n");
struct tree_node *left_array[100];
int num = -1;
/*统计叶子结点*/
tree_count_leaf(t, t->root, left_array, &num);
for (int i = 0; i<num; i++) {
/*黑高度不包括自身,所以初始值为-1*/
int black_height = -1;
tree_black_height(t, t->root, left_array[i], &black_height);
/*测试黑高度,从根到叶的路径上,黑结点数是一样的*/
printf("   根到叶子 :%d  的黑高度   :%d\n",
*(int*)left_array[i]->key, black_height);
}
printf("中序遍历结果:\n");
tree_inorder_walk(t, t->root, print_key);
printf("\n");
/*遍历树,释放结点的key*/
tree_destroy(t, free);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息