Binary Search Tree C语言实现

Posted createchance

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Binary Search Tree C语言实现相关的知识,希望对你有一定的参考价值。

Binary Search Tree是数据结构中比较有用的一种二叉树结构,这种结构讲大量的数据进行平摊式分布,并且规定大的数在右边,小的数在左边,以这种方式存放的数据可以非常方便地做数据排序和检索。
关于BST的更多信息,可以查看这个链接(英文,讲的非常好,不得不赞):http://algs4.cs.princeton.edu/32bst/
台湾国立清华大学韩永楷老师的MOOC(讲的超级棒,完爆国内,我的代码实现就是参考韩老师的课程内容):http://www.icourse163.org/course/NTHU-451013#/info
下面给出使用C语言的实现方式,我使用了最简单的方式实现,代码中有很多注释,大家可以参考。代码可编译,可运行。

/*************************************************************************
    > File Name: bst.c
    > Author: Baniel Gao
    > Mail: createchance@163.com 
    > Created Time: Thu 01 Dec 2016 08:29:23 AM EST
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>

typedef struct node_t 
    int key;
    struct node_t* parent;
    struct node_t* left;
    struct node_t* right;
 node;

/*
 * Get min number of this tree pointed by root.
 * 
 * Return min node pointer, NULL if root is NULL.
 */
node* min(node* root)

    node* min_node = root;

    if (root == NULL) 
        return NULL;
    

    while (min_node->left != NULL) 
        min_node = min_node->left;
    

    return min_node;


/*
 * Get max number of this tree pointed by root.
 * 
 * Return max node pointer, NULL if root is NULL.
 */
node* max(node* root)

    node* max_node = root;

    if (root == NULL)
    
        return NULL;
    

    while (max_node->right != NULL)
    
        max_node = max_node->right;
    

    return max_node;


/*
 * Search the number k.
 *
 * Return node pointer which contains the key, NULL if do not match anything.
 */
node* search(node* root, int k)

    node* current = root;

    if (root == NULL) 
        return NULL;
    

    while (1) 
        if (current->key == k) 
            break;
         else if (current->key > k) 
            current = current->left;
         else 
            current = current->right;
        

        if (current == NULL) 
            break;
        
    

    return current;


/*
 * Find the predeccessor of k.
 *
 * Return node pointer of predeccessor if success, NULL if find nothing.
 */
node* predecessor(node* root, int k)

    if (root == NULL)
    
        return NULL;
    

    node* target = search(root, k);
    if (target != NULL) 
        if (target->left != NULL) 
            target = max(target->left);
         else 
            while (1) 
                if (target->parent == NULL) 
                    target = target->parent;
                    break;
                 else if (target == target->parent->right) 
                    target = target->parent;
                    break;
                 else if (target == target->parent->left) 
                    target = target->parent;
                
            
        
    

    return target;


/*
 * Find successor of number k.
 * 
 * Return node pointer of successor if success, NULL if find nothing.
 */
node* successor(node* root, int k)

    if (root == NULL) 
        return NULL;
    

    node* target = search(root, k);
    if (target != NULL) 
        if (target->right != NULL) 
            target = min(target->right);
         else 
            while (1) 
                if (target->parent == NULL) 
                    target = target->parent;
                    break;
                 else if (target == target->parent->left) 
                    target = target->parent;
                    break;
                 else if (target == target->parent->right) 
                    target = target->parent;
                
            
        
    

    return target;


/*
 * insert one number k to binary search tree.
 *
 * Return node pointer if success, NULL if key already exists.
 */
node* insert(node* root, int k)

    node* current = root;

    if (root == NULL) 
        root = (node*) malloc(sizeof(node));
        root->key = k;
        return root;
    

    while (1) 
        if (current->key == k)
        
            current = NULL;
            break;
         else if (current->key > k) 
            if (current->left != NULL) 
                current = current->left;
             else 
                // no left child, so we are left child, create one node and insert.
                node* new = (node*) malloc(sizeof(node));
                new->key = k;
                new->parent = current;
                new->left = NULL;
                new->right = NULL;
                current->left = new;
                // move current to target node.
                current = current->left;
                break;
            
         else if (current->key < k) 
            if (current->right != NULL) 
                current = current->right;
             else 
                // no right child, so we are left child, create one node and insert.
                node* new = (node*) malloc(sizeof(node));
                new->key = k;
                new->parent = current;
                new->left = NULL;
                new->right = NULL;
                current->right = new;
                // move current to target node.
                current = current->right;
                break;
            
        
    

    return current;


/*
 * Delete node contains number k.
 * 
 * Return 0 if succeed, -1 if number k not found or tree root is NULL, 1 if the tree is empty after deletion.
 */
int delete(node* root, int k)

    if (root == NULL) 
        return -1;
    

    // Find this node first.
    node* target = search(root, k);

    // Well, we can not find this node.
    if (target == NULL) 
        return -1;
    

    /* Case 1: this node is leaf node. */
    if (target->left == NULL && target->right == NULL) 
        if (target != root) 
            if (target == target->parent->right) 
                target->parent->right = NULL;
             else 
                target->parent->left = NULL;
            
         else 
            root = NULL;
        
        free(target);
    
    /* Case 2: this node has only one child node. */
    else if (target->left != NULL && target->right == NULL) 
        // Case 2.1: this node only has a left child.
        if (target == root) 
            node* predecessor_node = predecessor(root, k);
            if (predecessor_node == NULL) 
                return -1;
            

            // Replace the number first.
            target->key = predecessor_node->key;
            // predecessor does not have any child.
            if (predecessor_node->left == NULL && predecessor_node->right == NULL) 
                if (target->right == predecessor_node) 
                    target->right = NULL;
                 else 
                    predecessor_node->parent->left = NULL;
                
            
            // predecessor only have left child.
            else 
                predecessor_node->parent->right = predecessor_node->left;
                predecessor_node->left->parent = predecessor_node->parent;
            
            // Free predecessor node.
            free(predecessor_node);
         else 
            target->left->parent = target->parent;
            if (target == target->parent->left) 
                target->parent->left = target->left;
             else 
                target->parent->right = target->left;
            
        
     else if (target->left == NULL && target->right != NULL) 
        // Case 2.2: this node only has a right child.
        if (target == root) 
            node* successor_node = successor(root, k);
            if (successor_node == NULL) 
                return -1;
            

            // Replace the number first.
            target->key = successor_node->key;
            // successor does not have any child.
            if (successor_node->left == NULL && successor_node->right == NULL) 
                if (target->right == successor_node) 
                    target->right = NULL;
                 else 
                    successor_node->parent->left = NULL;
                
            
            // successor only have right child.
            else 
                successor_node->parent->left = successor_node->right;
                successor_node->right->parent = successor_node->parent;
            
            // Free successor node.
            free(successor_node);
         else 
            target->right->parent = target->parent;
            if (target == target->parent->left) 
                target->parent->left = target->right;
             else 
                target->parent->right = target->right;
            
        
    
    /* Case 3: this node has two child node. */
    else if (target->left != NULL && target->right != NULL) 
        node* successor_node = successor(root, k);
        if (successor_node == NULL) 
            return -1;
        

        // Replace the number first.
        target->key = successor_node->key;
        // Case 3.1: successor does not have any child.
        if (successor_node->left == NULL && successor_node->right == NULL) 
            if (target->right == successor_node) 
                target->right = NULL;
             else 
                successor_node->parent->left = NULL;
            
        
        // Case 3.2: successor only have right child.
        else 
            successor_node->parent->left = successor_node->right;
            successor_node->right->parent = successor_node->parent;
        
        // Free successor node.
        free(successor_node);
    

    if (root == NULL) 
        return 1;
    

    return 0;


/*
 * Modify one node'key. Change it from src to dst.
 *
 * Return the node modified, NULL if this node does not exist.
 */
node* modify(node* root, int src, int dst)

    if (root == NULL) 
        return NULL;
    

    // We have to make sure the src exists and dst does not exist.
    node* source = search(root, src);
    node* destination = search(root, dst);

    if (source == NULL) 
        printf("The source number %d does not exist. \\n", src);
        return NULL;
    

    if (destination != NULL) 
        printf("The destination number %d already exist. \\n", dst);
        return NULL;
    

    // we delete the old node first.
    delete(root, src);
    // then insert new node.
    insert(root, dst);

    return source;


/*
 * Print this tree by inorder.
 * 
 * The numbers printed is sorted.
 */
void print_tree_inorder(node* root) 
    if(root != NULL) 
        print_tree_inorder(root->left);
        printf("%d ",root->key);
        print_tree_inorder(root->right);
    


/*
 * Console helper function.
 */
void show_help()

    printf("1. insert\\n");
    printf("2. delete\\n");
    printf("3. modify\\n");
    printf("4. search\\n");
    printf("5. predeccessor\\n");
    printf("6. successor\\n");
    printf("7. min\\n");
    printf("8. max\\n");
    printf("9. print tree\\n");


int main()

    char cmd;
    int key, key2;
    node* root = NULL;

    printf("This is a binary search tree demo.\\n");
    while (1) 
        printf("Command<m for help>: ");
        fflush(stdout);
        scanf("%c", &cmd);

        if (cmd == 'm') 
            show_help();
         else if (cmd == '1') 
            printf("Input number to insert: ");
            fflush(stdout);
            scanf("%d", &key);
            node* inserted_node = insert(root, key);
            if (root == NULL) 
                root = inserted_node;
            
            if (inserted_node == NULL) 
                printf("The number %d already exist. \\n", key);
             else 
                printf("Complete!\\n");
            
         else if (cmd == '2') 
            printf("Input number to delete: ");
            fflush(stdout);
            scanf("%d", &key);
            int ret = delete(root, key);
            if (ret < 0) 
                printf("The numnber %d does not exist. \\n", key);
             else if (ret == 1) 
                printf("The tree is empty now. \\n");
                root = NULL;
             else 
                printf("Complete!\\n");
            
         else if (cmd == '3') 
            printf("Input the number you want to change from and to: ");
            fflush(stdout);
            scanf("%d %d", &key, &key2);
            node* modified_node = modify(root, key, key2);
            if (modified_node == NULL) 
                printf("Modify failed. \\n");
             else 
                printf("Complete!\\n");
            
         else if (cmd == '4') 
            printf("Input the number you want to search: ");
            fflush(stdout);
            scanf("%d", &key);
            node* result = search(root, key);
            if (result == NULL) 
                printf("The number %d does not exist.\\n", key);
             else 
                printf("Complete!\\n");
            
         else if (cmd == '5') 
            printf("Input the number you want to find predecessor: ");
            fflush(stdout);
            scanf("%d", &key);
            node* result = predecessor(root, key);
            if (result == NULL) 
                printf("Predecessor do not found!\\n");
             else 
                printf("Predecessor is %d. \\n", result->key);
            
         else if (cmd == '6') 
            printf("Input the number you want to find successor: ");
            fflush(stdout);
            scanf("%d", &key);
            node* result = successor(root, key);
            if (result == NULL) 
                printf("Successor do not found!\\n");
             else 
                printf("Successor is %d. \\n", result->key);
            
         else if (cmd == '7') 
            node* result = min(root);
            if (result != NULL) 
                printf("Min number is: %d. \\n", result->key);
             else 
                printf("This tree is empty! \\n");
            
         else if (cmd == '8') 
            node* result = max(root);
            if (result != NULL) 
                printf("Max number is: %d. \\n", result->key);
             else 
                printf("This tree is empty! \\n");
            
         else if (cmd == '9') 
            if (root != NULL) 
                print_tree_inorder(root);
                printf("\\n");
             else 
                printf("This tree is empty! \\n");
            
        

        getchar();
    

    return 0;

上面程序支持9中操作:
1. insert:插入一个数据,如果当前bst为空,那么新建根节点,并且赋值
2. delete:删除一个数据,如果给定数字不存在,则删除失败
3. modify:修改一个数据,需要源数据存在,且目标数据不能存在
4. search:检索一个数据,如果数据存在成功返回,反之失败
5. predeccessor:检索一个数的前导数(这个数必须存在于树中),就是比目标数小的所有数的最大数
6. successor:检索一个数的后导数(这个数必须存在于数中),就是比目标数大的所有数的最小数
7. min:检索树中最小的数
8. max:检索树中最大的数
9. print tree:按照中序打印树,对于BST来说中序就是所有数的升序排序
分别输入以上操作前的序号,就可以对BST发起操作。运行如下图:

以上是关于Binary Search Tree C语言实现的主要内容,如果未能解决你的问题,请参考以下文章

[数据结构]10.2实现binary search tree的查找和插入操作,用非递归的方法实现

[LinkList/Tree]109. Convert Sorted List to Binary Search Tree

Convert Sorted Array to Binary Search Tree & Convert Sorted List to Binary Search Tree

LeetCode Closest Binary Search Tree Value

LeetCode98. Validate Binary Search Tree

Binary Search Tree