二叉查找树

1、二叉查找树(也叫二叉搜索树,或二叉排序树)或者是一棵空树,或者是具有下列性质的二叉树:

1)若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;

2)若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;

3)它的左、右子树也分别为二叉查找树。


2、二叉查找树的基本运算 

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. typedef int data_type;  
  5.   
  6. typedef struct bst_node {  
  7.     data_type data;  
  8.     struct bst_node *lchild, *rchild;  
  9. }bst_t, *bst_p;  


1)插入

在二叉查找树中插入新结点,要保证插入新结点后仍能满足二叉查找树的性质。例子中的插入过程如下:

a、若二叉查找树root为空,则使新结点为根;

b、若二叉查找树root不为空,则通过search_bst_for_insert函数寻找插入点并返回它的地址(若新结点中的关键字已经存在,则返回空指针);

 c、若新结点的关键字小于插入点的关键字,则将新结点插入到插入点的左子树中,大于则插入到插入点的右子树中。 

  1. static bst_p search_bst_for_insert(bst_p *root, data_type key)  
  2. {  
  3.     bst_p s, p = *root;  
  4.   
  5.     while (p) {  
  6.     s = p;  
  7.   
  8.     if (p->data == key)  
  9.         return NULL;  
  10.   
  11.     p = (key < p->data) ? p->lchild : p->rchild;  
  12.     }  
  13.   
  14.     return s;  
  15. }  
  16.   
  17. void insert_bst_node(bst_p *root, data_type data)  
  18. {  
  19.     bst_p s, p;  
  20.   
  21.     s = malloc(sizeof(struct bst_node));  
  22.     if (!s)  
  23.     perror("Allocate dynamic memory");  
  24.   
  25.     s -> data = data;  
  26.     s -> lchild = s -> rchild = NULL;  
  27.   
  28.     if (*root == NULL)  
  29.     *root = s;  
  30.     else {  
  31.     p = search_bst_for_insert(root, data);  
  32.     if (p == NULL) {  
  33.         fprintf(stderr, "The %d already exists.\n", data);  
  34.         free(s);  
  35.         return;  
  36.     }  
  37.   
  38.     if (data < p->data)  
  39.         p->lchild = s;  
  40.     else  
  41.         p->rchild = s;  
  42.     }  
  43. }  


2)遍历

  1. static int print(data_type data)  
  2. {  
  3.     printf("%d ", data);  
  4.   
  5.     return 1;  
  6. }  
  7.   
  8. int pre_order_traverse(bst_p root, int (*visit)(data_type data))   
  9. {  
  10.     if (root) {  
  11.     if (visit(root->data))  
  12.         if (pre_order_traverse(root->lchild, visit))  
  13.             if (pre_order_traverse(root->rchild, visit))  
  14.                 return 1;  
  15.     return 0;  
  16.     }  
  17.     else  
  18.     return 1;  
  19. }  
  20.   
  21. int post_order_traverse(bst_p root, int (*visit)(data_type data))  
  22. {  
  23.     if (root) {  
  24.     if (post_order_traverse(root->lchild, visit))  
  25.         if (visit(root->data))  
  26.         if (post_order_traverse(root->rchild, visit))  
  27.             return 1;  
  28.     return 0;  
  29.     }  
  30.     else  
  31.     return 1;  
  32. }  
  

中序遍历二叉查找树可得到一个关键字的有序序列。

3)删除

删除某个结点后依然要保持二叉查找树的特性。例子中的删除过程如下:

a、若删除点是叶子结点,则设置其双亲结点的指针为空。

b、若删除点只有左子树,或只有右子树,则设置其双亲结点的指针指向左子树或右子树。

c、若删除点的左右子树均不为空,则:

1)、查询删除点的右子树的左子树是否为空,若为空,则把删除点的左子树设为删除点的右子树的左子树。

2)、若不为空,则继续查询左子树,直到找到最底层的左子树为止。

  1. void delete_bst_node(bst_p *root, data_type data)  
  2. {  
  3.     bst_p p = *root, parent, s;  
  4.   
  5.     if (!p) {  
  6.     fprintf(stderr, "Not found %d.\n", data);  
  7.     return;  
  8.     }  
  9.   
  10.     if (p->data == data) {  
  11.     /* It's a leaf node */  
  12.     if (!p->rchild && !p->lchild) {  
  13.         *root = NULL;  
  14.         free(p);  
  15.     }  
  16.     /* the right child is NULL */  
  17.     else if (!p->rchild) {  
  18.         *root = p->lchild;  
  19.         free(p);  
  20.     }  
  21.     /* the left child is NULL */  
  22.     else if (!p->lchild) {  
  23.         *root = p->rchild;  
  24.         free(p);  
  25.     }  
  26.     /* the node has both children */  
  27.     else {  
  28.         s = p->rchild;  
  29.         /* the s without left child */  
  30.         if (!s->lchild)  
  31.         s->lchild = p->lchild;  
  32.         /* the s have left child */  
  33.         else {  
  34.         /* find the smallest node in the left subtree of s */  
  35.         while (s->lchild) {  
  36.             /* record the parent node of s */  
  37.             parent = s;  
  38.             s = s->lchild;  
  39.         }  
  40.         parent->lchild = s->rchild;  
  41.         s->lchild = p->lchild;  
  42.         s->rchild = p->rchild;  
  43.         }  
  44.         *root = s;  
  45.         free(p);  
  46.     }  
  47.     }   
  48.     else if (data > p->data) {  
  49.     delete_bst_node(&(p->rchild), data);  
  50.     }   
  51.     else if (data < p->data) {  
  52.     delete_bst_node(&(p->lchild), data);  
  53.     }  
  54. }  


4、二叉查找树的查找分析

同样的关键字,以不同的插入顺序,会产生不同形态的二叉查找树。 

  1. int main(int argc, char *argv[])  
  2. {  
  3.     int i, num;  
  4.     bst_p root = NULL;  
  5.   
  6.     if (argc < 2) {  
  7.     fprintf(stderr, "Usage: %s num\n", argv[0]);  
  8.     exit(-1);  
  9.     }  
  10.   
  11.     num = atoi(argv[1]);  
  12.     data_type arr[num];  
  13.     printf("Please enter %d integers:\n", num);  
  14.     for (i = 0; i < num; i++) {  
  15.     scanf("%d", &arr[i]);  
  16.     insert_bst_node(&root, arr[i]);  
  17.     }  
  18.   
  19.     printf("\npre order traverse: ");  
  20.     pre_order_traverse(root, print);  
  21.     printf("\npost order traverse: ");  
  22.     post_order_traverse(root, print);  
  23.     printf("\n");  
  24.   
  25.     delete_bst_node(&root, 45);  
  26.   
  27.     printf("\npre order traverse: ");  
  28.     pre_order_traverse(root, print);  
  29.     printf("\npost order traverse: ");  
  30.     post_order_traverse(root, print);  
  31.     printf("\n");  
  32.       
  33.     return 0;  
  34. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值