搜索二叉树代码实现简析

版权声明:本文为博主原创文章,转载请标明出处! https://blog.csdn.net/qq_27396861/article/details/54382155
> 树和节点

typedef struct tree_node_t
{
    struct tree_node_t* left;
    struct tree_node_t* right;
    struct tree_node_t* parent;
    int value;
} tree_node_t;

typedef struct tree_t
{
    tree_node_t* head;
} tree_t;


> 安装节点画图软件

sudo apt-get install graphviz
自带dot命令。

> graphviz的使用格式:

void tree_draw_node(tree_node_t* node, FILE* fp)
{
    if(node == NULL)
        return;

    // 绘制点
    /*
     * node[shape=record,style=filled,color=black,fontcolor=white];
     * 93[label="<f0> | <f1> 93 | <f2> "];
     * */

    fprintf(fp, "node[shape=record];%d[label=\"<f0>|<f1> %d|<f2>\"];\n", node->value, node->value);

    // 绘制线条
    if(node->parent != NULL)
    {
        // 93:f0:se->37:f1;
        if(node == node->parent->left)
            fprintf(fp, "%d:f0:sw->%d:f1;\n", node->parent->value, node->value);
        else
            fprintf(fp, "%d:f2:se->%d:f1;\n", node->parent->value, node->value);
    }


    // 递归遍历
    tree_draw_node(node->left, fp);
    tree_draw_node(node->right, fp);
}

void tree_print(tree_t* tree, const char* filename)
{
    FILE* fp = fopen(filename, "w");
    fprintf(fp, "digraph G{\n");

    tree_draw_node(tree->head, fp);

    fprintf(fp, "}\n");
    fclose(fp);

    // xxx.dot
    char cmd[2048];
    sprintf(cmd, "dot %s -Tpng -o %s.png", filename, filename);
    popen(cmd, "r");
}

> 初始化树和节点

void tree_init(tree_t* tree)
{
    tree->head = NULL;
}

void tree_init_node(tree_node_t* node)
{
    node->left = node->right = node->parent = NULL;
}

> 节点的插入:

void tree_insert(tree_t* tree, int value)
{
    tree_node_t* node = malloc(sizeof(tree_node_t));
    tree_init_node(node);
    node->value = value;

    if(tree->head == NULL)
    {
        tree->head = node;
        return;
    }

    tree_node_t* parent = tree->head;
    while(1)
    {
        if(parent->value > value)
        {
            if(parent->left == NULL)
            {
                parent->left = node;
                node->parent = parent;
                break;
            }
            parent = parent->left;
        }
        else
        {
            if(parent->right == NULL)
            {
                parent->right = node;
                node->parent = parent;
                break;
            }
            parent = parent->right;
        }
    }
}

> 节点的查找

tree_node_t* tree_find(tree_t* tree, int value)
{
    if ( NULL == tree)
    {
        return;
    }

    if (tree->head->value == value)
    {
        return tree->head;
    }

    tree_node_t* node = tree->head;
    while (node)
    {
        if (value < node->value)
        {
            node = node->left;
        }
        else if (value > node->value)
        {
            node = node->right;
        }
        else
        {
            break;
        }
    }

    return node;
}

> 节点的删除

// 并不是真的删除节点而是用节点左边的最大值或者右边的最小值来覆盖节点
void tree_remove(tree_t* tree, tree_node_t* node)
{
    if (NULL == tree || NULL == node)
    {
        return ;
    }

     // 先选取节点右边的最大值替换要删除的节点的值
    tree_node_t* left = node->left;
    if (left)
    {
        tree_node_t* leftMax = left->right;
        if (leftMax == NULL)      // 当left右边没有节点的时候,left就是最大值节点
        {
            leftMax = left;
        }
        else
        {
            while (leftMax->right)     // 1、找到左边的最大值
            {
                leftMax = leftMax->right;     
            }
        }

        node->value = leftMax->value;     // 2、找到最大值后,覆盖要删除节点的值

          // 3、将最大值节点的左节点的值,挂到覆盖节点的 右边 / 左边( 不然后面的节点就没有挂上,,,重要
        if (leftMax->parent->right == leftMax)     // 
        {
            leftMax->parent->right = leftMax->left;
        }
        else
        {
            leftMax->parent->left = leftMax->left;
        }
        free(leftMax);
        leftMax = NULL;
    }
    else    // 选取节点右边的最大值替换要删除的节点的值
    {
        tree_node_t* right = node->right;
        if (right)
        {
            tree_node_t* rightMin = right->left;
            if (NULL == rightMin)
            {
                rightMin = right;
            }
            else
            {
                while (rightMin->left)
                {
                    rightMin = rightMin->left;
                }
            }

            node->value = rightMin->value;

               // 3、将最小节点的右节点挂到 覆盖后节点的 右边 / 左边 ( 不然后面的节点没有挂上,,,重要
            if (rightMin->parent->right == rightMin)
            {
                rightMin->parent->right = rightMin->right;
            }
            else
            {
                rightMin->parent->left = rightMin->right;
            }
        }
        else     // 没有左节点,也没有右节点,那就是根节点。
        {
            free(tree->head);
            tree->head = NULL;
        }
    }
}


> 搜索二叉树的左旋:

void tree_rotate_left(tree_t* tree, tree_node_t* node)
{
    tree_node_t* right = node->right;
    if(right == NULL)
        return;
    // parent可能为空
    tree_node_t* parent = node->parent;

    // 1. 将原先node节点的右边的最小值,移到 后来node的右边
    node->right = right->left;
    if(right->left) right->left->parent = node;

     // 2. 父子节点换位置
    right->left = node;
    node->parent = right;

     // 3. 旋转后parent节点的指向
    right->parent = parent;
    if(parent)
    {
        if(parent->left == node) parent->left = right;
        else parent->right = right;
    }
    else
    {
        tree->head = right;
    }
}


> 搜索二叉树的右旋:

void tree_rotate_right(tree_t* tree, tree_node_t* node)
{
    tree_node_t* left = node->left;
    if(left == NULL) return;
    tree_node_t* parent = node->parent;

     // 1. 将原先node节点左边的最大值,移动到后来Node节点的左边
    node->left = left->right;
    if(left->right) left->right->parent = node;

     // 2. 父子节点的指向
    left->right = node;
    node->parent = left;

     // 3. 旋转后parent节点的指向
    left->parent = parent;
    if(parent)
    {
        if(parent->right == node) parent->right = left;
        else parent->left = left;
    }
    else
    {
        tree->head = left;
    }
}


猜你喜欢

转载自blog.csdn.net/qq_27396861/article/details/54382155