0
点赞
收藏
分享

微信扫一扫

binary search tree: data structure

烟中雯城 2021-09-30 阅读 54

1 二叉 搜索/排序 树

算法 分析 + 伪代码 + 图示 见 如下链接

https://www.jianshu.com/p/f634b2f1839e

// 1. 
// BinaryTree.h
#ifndef _BINARYTREE_H
#define _BINARYTREE_H

typedef struct B_tree_node 
{
    int                 key; 
    struct B_tree_node* parent;
    struct B_tree_node* lchild;  
    struct B_tree_node* rchild; 
}B_tree_node;

B_tree_node* 
create_node(int key);

void 
connect_nodes(B_tree_node* _parent, 
              B_tree_node* _lchild, 
              B_tree_node* _rchild);

void 
destory_tree(B_tree_node* proot);
              
void 
print_node_and_child(B_tree_node* pnode);

void 
print_tree(B_tree_node* proot);
              
#endif
// 2.
// BinaryTree.cpp
#include <cstdio>
#include <stdlib.h>    // malloc / free
#include "BinaryTree.h"

B_tree_node* 
create_node(int key)
{
    B_tree_node* pnode = (B_tree_node*)malloc( sizeof(B_tree_node) );
    
    pnode->key = key;
    pnode->parent = NULL;
    pnode->lchild = NULL;
    pnode->rchild = NULL;

    return pnode;
}

void 
connect_nodes(B_tree_node* _parent, 
              B_tree_node* _lchild, 
              B_tree_node* _rchild)
{
    if(_parent != NULL)
    {
        _parent->lchild = _lchild;
        _parent->rchild = _rchild;
    }
    if(_lchild != NULL)
        _lchild->parent = _parent;
    if(_rchild != NULL)
        _rchild->parent = _parent;
}

void
destory_tree(B_tree_node* proot)
{
    if (proot != NULL)
    {
        B_tree_node* lchild = proot->lchild;
        B_tree_node* rchild = proot->rchild;

        free(proot);
        proot = NULL;

        destory_tree(lchild);
        destory_tree(rchild);
    }
}

void 
print_node_and_child(B_tree_node* pnode)
{
    if(pnode != NULL)
    {
        printf("node key: %d\n", pnode->key);

        if(pnode->lchild != NULL)
            printf("lchild key: %d.\n", pnode->lchild->key);
        else
            printf("lchild is null.\n");

        if(pnode->rchild != NULL)
            printf("rchild key: %d.\n", pnode->rchild->key);
        else
            printf("rchild key is null.\n");
    }
    else
        printf("this node is null.\n");
}

void 
print_tree(B_tree_node* proot)
{
    print_node_and_child(proot);

    if(proot != NULL)
    {
        if(proot->lchild != NULL)
            print_tree(proot->lchild);

        if(proot->rchild != NULL)
            print_tree(proot->rchild);
    }
}
// 3.
// b_tree_client.cpp : Defines the entry point for the console application.
// binary order tree
#include <cstdio>
#include <iostream>
#include <vector>
#include <stack>
#include "BinaryTree.h"

//---1. traverse: preorder / inorder / postorder 
// 先 根/序: 根 -> 左 -> 右
// recursion version:
void
preorder_tree_walk(B_tree_node* walk)
{
    if (walk != NULL)
    {
        printf("%d ", walk->key);
        preorder_tree_walk(walk->lchild);
        preorder_tree_walk(walk->rchild);
    }
}

// iteration version:
// 用 栈, 时/空 复杂度 O(N)
std::vector<int>
preorder_tree_walk_iter(B_tree_node* proot)
{
    //(1) vector: 存 output sequence
    std::vector<int> result_vec;

    //(2) stack: 存 即将 遍历的 pnode, 
    //           后 进 先 出/遍历
    std::stack<const B_tree_node*> stk;

    //(3) root pointer 先入栈
    if (proot != nullptr)
        stk.push(proot);

    //(4) stack 再循环: 若 栈 not empty
    while (!stk.empty())
    {
        // 1) get/top old_top elem/pnode
        // 2) pop top elem
        // 3) old_top.key 入 vector
        // 4) old_top->rchild 入栈
        // 5) old_top->lchild 入栈
        const B_tree_node* p = stk.top();
        stk.pop();

        result_vec.push_back(p->key);

        if (p->rchild != nullptr)
            stk.push(p->rchild);
        if (p->lchild != nullptr)
            stk.push(p->lchild);
    }

    for (std::vector<int>::iterator
        iter = result_vec.begin();
        iter != result_vec.end();
        ++iter)
        std::cout << *iter << ' ' << std::endl;

    return result_vec;
}

// 中序: 左 -> 根 -> 右
// 以 walk 为 root 的 子树
// recursion version:
void 
inorder_tree_walk(B_tree_node* walk)
{
    if (walk != NULL)
    {
        inorder_tree_walk(walk->lchild);
        printf("%d ", walk->key);
        inorder_tree_walk(walk->rchild);
    }
}

// iteration version:
std::vector<int>
inorder_tree_walk_iter(B_tree_node* proot)
{
    std::vector<int> result_vec;
    std::stack<const B_tree_node*> stk;
    const B_tree_node* p = proot;

    // out:
    // case1: stk empty
    // case2: p == NULL
    while ( !stk.empty() || p != nullptr)
    {
        //(1) pnode != NULL 时, 沿左孩子 push + 左下
        if (p != nullptr) 
        {
            stk.push(p);
            p = p->lchild;
        }
        else //(2) 直到 不能再 左下(pnode == NULL/ old_pnode->lchild == NULL)
        {
            // 1) get/top old_pnode elem/pnode
            p = stk.top();

            // 2) old_pnode.key 入 vector
            result_vec.push_back(p->key);

            // 3) pop old_pnode
            stk.pop();
            
            // 4) get old_top->rchild, 
            //    ready to be processd in next iteration
            p = p->rchild;
        }
    }

    for (std::vector<int>::iterator
        iter = result_vec.begin();
        iter != result_vec.end();
        ++iter)
        std::cout << *iter << ' ' << std::endl;

    return result_vec;
}

// 后序: 左 -> 右 -> 根
void 
postorder_tree_walk(B_tree_node* walk)
{
    if (walk != NULL)
    {
        postorder_tree_walk(walk->lchild);
        postorder_tree_walk(walk->rchild);
        printf("%d ", walk->key);
    }
}

// iteration version:
// 需要 record 刚 访问过 的 node
std::vector<int>
postorder_tree_walk_iter(B_tree_node* proot)
{
    std::vector<int> result_vec;
    std::stack<const B_tree_node*> s;
    const B_tree_node* cur = proot, // current_visiting
        *just_visited = nullptr;
    
    // 2 层 循环
    do 
    {
        //(1) 以 current 为 root, 沿左孩子 push + 左下,
        //    找到 左孩子为空 的 pnode:
        // out:
        // cur == NULL / old_cur->lchild == NULL
        while (cur != nullptr)
        { 
            s.push(cur);
            cur = cur->lchild;
        }

        // (2) 循环处理 old_cur 及其 右子树
        // 1) just_visited 必须先 置空
        just_visited = nullptr;

        while ( !s.empty() ) 
        {
            // 2) get/top old_cur
            cur = s.top();

            // 3) old_cur 先 pop
            s.pop();
           
            // 4) 若 old_cur->rchild 刚已访问,
            //    则, 下来该 访问 old_cur:
            //    1> old_cur->key 入 vector
            //    2> just_visited 更新为 old_cur
            //    case1: cur->rchild == just_visited == NULL
            //    case2: cur->rchild == just_visited != NULL
            if (cur->rchild == just_visited) 
            {
                result_vec.push_back(cur->key);
                just_visited = cur;
            }
            else // 若 old_cur->rchild 刚没访问
            {
                //1> old_cur 再次 push
                s.push(cur);

                //2> 先 process 右子树 
                // cur 更新 为 old_cur->rchild
                cur = cur->rchild;

                //3> 跳出 内层 循环
                break;
            }
        }
    } while (!s.empty());

    for (std::vector<int>::iterator
        iter = result_vec.begin();
        iter != result_vec.end();
        ++iter)
        std::cout << *iter << ' ' << std::endl;

    return result_vec;
}

//---2. find: 指定 / 最小 / 最大 node 
//            指定 node 的 next / prev
// (1)
B_tree_node*
tree_search(B_tree_node* walk, int key)
{
    // until: walk == NIL or walk.key == key(隐含 walk != NIL )
    while (walk != NULL && walk->key != key)
    {
        if (key < walk->key)
            walk = walk->lchild;
        else
            walk = walk->rchild;
    }
    return walk;
}

//(2)
B_tree_node*
tree_minimum(B_tree_node* walk)
{
    // out: walk == NULL or walk->lchild == NULL(隐含 walk != NULL)
    while (walk != NULL && walk->lchild != NULL)
        walk = walk->lchild;
    return walk;
}

//(3) 与 tree_minimum 对称
B_tree_node*
tree_maximum(B_tree_node* walk)
{
    while (walk != NULL && walk->rchild != NULL)
        walk = walk->rchild;
    return walk;
}

// (4)
B_tree_node*
tree_successor(B_tree_node* walk)
{
    if (walk == NULL)
        return walk;
    // below 初始 必 walk != NIL

    // walk 有 右孩子 -> 后继 为 右孩子 最小值
    if (walk->rchild != NULL) 
        return tree_minimum(walk->rchild);
    // below 初始 必 walk != NIL, walk.rchild == NIL

    // 取 walk.p -> 据 walk 是 root / lchild / rchild 分别处理
    B_tree_node* walk_p = walk->parent;

    // walk 一直 左上(walk 为 rchild 才能满足 能左上 的 条件), 
    // until walk 无法左上
    // while exit:
    // case1: walk_p == NULL => walk == root
    // case2: walk_p != NULL && walk == walk_p.lchild 
    // note: while 每次迭代 前后 必 walk != NIL
    while (walk_p != NULL && walk == walk_p->rchild)
    {
        walk = walk_p;           //== walk.p => walk 往 左上走
        walk_p = walk_p->parent; //== walk.p => walk_p 联动为 walk.p, 也往 左上走
    }
    return walk_p;
}

// (5) 与 tree_successor 对称
B_tree_node*
tree_predecessor(B_tree_node* walk)
{
    if (walk == NULL)
        return walk;
    if (walk->lchild != NULL)
        return tree_maximum(walk->lchild);

    B_tree_node* walk_p = walk->parent;

    while (walk_p != NULL && walk == walk_p->lchild)
    {
        walk = walk_p; 
        walk_p = walk_p->parent; 
    }
    return walk_p;
}

//---3. insert / delete
// 可能改变 根指针 => 将 根指针 的 指针 传进来 
void
tree_insert(B_tree_node** proot, B_tree_node* z)
{
    B_tree_node* walk_p = NULL;
    B_tree_node* walk = *proot;

    // loop out: walk == NIL
    // if while execute >= 1 time // Tree not empty 
    //   => after every iteration, 
    //      walk_p/walk_old != NIL
    // else execute == 0 time     // Tree empty
    //   =>  walk == *proot == NIL, walk_p = NIL
    while (walk != NULL)
    {
        walk_p = walk;

        if(z->key < walk->key)
            walk = walk->lchild;
        else  // >=
            walk = walk->rchild;
    }
    // below: firstly walk == NIL

    // link z <-> z.parent / walk_p / y 
    z->parent = walk_p;

    if (walk_p == NULL)
        *proot = z;     // 改变 根指针
    else if (z->key < walk_p->key) // below: walk_p != NIL
        walk_p->lchild = z;
    else
        walk_p->rchild = z;
}

// 可能改变 根指针 => 将 根指针 的 指针 传进来 
void 
transplant(B_tree_node** proot, 
           B_tree_node* u, 
           B_tree_node* v)
{
    if (u == *proot && u == NULL)
        *proot = v;

    if (u->parent == NULL)   // u == *proot
        *proot = v;
    else if (u == u->parent->lchild) // below: firstly u.p != NIL
        u->parent->lchild = v;
    else // if u == u.p.rchild
        u->parent->rchild = v;

    if (v != NULL)
        v->parent = u->parent;
}

void
tree_delete(B_tree_node** proot, B_tree_node* z)
{
    if (z->lchild == NULL)        // below: firstly z.lchild != NIL // 可 z.rchild == NIL
        transplant(proot, z, z->rchild);
    else if (z->rchild == NULL)   // z.lchild != NIL && z.rchild == NIL 
        transplant(proot, z, z->lchild);
    else                      // z.lchild != NIL && z.rchild != NIL
    {
        B_tree_node* y = tree_minimum(z->rchild); // z_next / y

        if( y->parent != z )
        {
            //(1)
            transplant(proot, y, y->rchild);

            //(2) link y <-> z.rchild
            y->rchild = z->rchild;
            y->rchild->parent = y;
        }
        //(3)
        transplant(proot, z, y);

        //(4) link y<-> z.lchild
        y->lchild = z->lchild;
        y->lchild->parent = y;
    }

}
//---4. depth

// 用 queue, 时/空 复杂度 O(N)
std::vector<int>
BFS_tree_walk(B_tree_node* proot)
{
    //(1) vector: 存 output sequence
    std::vector<int> result_vec;

    //(2) queue: 存 即将 遍历的 pnode, 
    //           后 进 先 出/遍历
    std::queue<const B_tree_node*> que;

    //(3) root pointer 先入栈
    if (proot != nullptr)
        que.push(proot);

    //(4) stack 再循环: 若 栈 not empty
    while (!que.empty())
    {
        // 1) get/top old_top elem/pnode
        // 2) pop top elem
        // 3) old_top.key 入 vector
        // 4) old_top->lchild 入 queue
        // 5) old_top->rchild 入 queue
        const B_tree_node* p = que.front();
        que.pop();

        result_vec.push_back(p->key);

        if (p->lchild != nullptr)
            que.push(p->lchild);
        if (p->rchild != nullptr)
            que.push(p->rchild);
    }

    for (std::vector<int>::iterator
        iter = result_vec.begin();
        iter != result_vec.end();
        ++iter)
        std::cout << *iter << ' ' << std::endl;

    return result_vec;
}

int tree_depth(B_tree_node* proot)
{
    if(proot == NULL)
        return 0;

    int ldepth = tree_depth(proot->lchild);
    int rdepth = tree_depth(proot->rchild);

    return (ldepth > rdepth) ? (ldepth + 1) : (rdepth + 1);
}

// ====================test cases:====================
void 
Test(B_tree_node** pnode, B_tree_node* z)
{
    // ---1. walk
    // inorder_tree_walk(pnode);
    // preorder_tree_walk_iter(pnode);
    // inorder_tree_walk_iter(pnode);
    // postorder_tree_walk_iter(pnode);
    
    //--- 2. find
    /*
    B_tree_node* result = tree_search(pnode, 5);
    if (result)
        printf("found");
    else
        printf("not found");
    */

    /*
    B_tree_node* result = tree_maximum(pnode);
    // B_tree_node* result = tree_minimum(pnode);
    if (result)
        printf("found: %d", result->key );
    else
        printf("not found");
    */

    /*
    B_tree_node* result = tree_predecessor(pnode);
    //B_tree_node* result = tree_successor(pnode);
    if (result)
        printf("found successor: %d", result->key);
    else
        printf("not found successor:");
    */
    
    //--- 3. insert / delete
    //B_tree_node* pnode_new = create_node(8);
    //tree_insert(pnode, pnode_new);

    tree_delete(pnode, z);
    //--- 4. depth

    printf("\n");
}

void 
Test_tree_depth(B_tree_node* proot, 
                int          expected_result)
{
    int result = tree_depth(proot);

    if(expected_result == result)
        printf("Test passed.\n");
    else
        printf("Test failed.\n");
}

//           5
//         /   \
//        2     6
//       /\      \
//      1  4      7
//        /
//       3
void Test1()
{
    printf("Test1 begins.\n");

    B_tree_node* pnode1 = create_node(5);
    B_tree_node* pnode2 = create_node(2);
    B_tree_node* pnode3 = create_node(6);
    B_tree_node* pnode4 = create_node(1);
    B_tree_node* pnode5 = create_node(4);
    B_tree_node* pnode6 = create_node(7);
    B_tree_node* pnode7 = create_node(3);

    connect_nodes(pnode1, pnode2, pnode3);
    connect_nodes(pnode2, pnode4, pnode5);
    connect_nodes(pnode3, NULL, pnode6);
    connect_nodes(pnode5, pnode7, NULL);

    //Test(pnode5);
    //Test(pnode7);
    Test(&pnode1, pnode2);

    print_tree(pnode1);
    destory_tree(pnode1);
}

//           5
//          /
//        4
//       /
//      3
//     /
//    2
//   /
//  1
void Test2_left_list()
{
    printf("Test2_left_list begins.\n");

    B_tree_node* pnode1 = create_node(5);
    B_tree_node* pnode2 = create_node(4);
    B_tree_node* pnode3 = create_node(3);
    B_tree_node* pnode4 = create_node(2);
    B_tree_node* pnode5 = create_node(1);

    connect_nodes(pnode1, pnode2, NULL);
    connect_nodes(pnode2, pnode3, NULL);
    connect_nodes(pnode3, pnode4, NULL);
    connect_nodes(pnode4, pnode5, NULL);

    Test(&pnode1, pnode3);

    print_tree(pnode1);

    destory_tree(pnode1);
}

//  1
//   \
//    2
//     \
//      3
//       \
//        4
//         \
//          5
void Test3_right_list()
{
    printf("Test3_right_list begins.\n");

    B_tree_node* pnode1 = create_node(1);
    B_tree_node* pnode2 = create_node(2);
    B_tree_node* pnode3 = create_node(3);
    B_tree_node* pnode4 = create_node(4);
    B_tree_node* pnode5 = create_node(5);

    connect_nodes(pnode1, NULL, pnode2);
    connect_nodes(pnode2, NULL, pnode3);
    connect_nodes(pnode3, NULL, pnode4);
    connect_nodes(pnode4, NULL, pnode5);

    Test(&pnode1, pnode3);

    print_tree(pnode1);

    destory_tree(pnode1);
}

void Test4_only_one_node()
{
    printf("Test4_only_one_node begins.\n");

    B_tree_node* pnode1 = create_node(1);
    
    Test(&pnode1, pnode1);
    print_tree(pnode1);
    destory_tree(pnode1);
}

void Test5_empty_tree()
{
    printf("Test5_empty_tree begins.\n");

    //Test(NULL);
}

int main()
{
    Test1();
    Test2_left_list();
    Test3_right_list();
    Test4_only_one_node();
    //Test5_empty_tree();

    return 0;
}

2 遍历 迭代版

morris 遍历:

原理: 利用 leaf node 左右孩子为 nullptr, 来 压缩空间

`将 迭代版二叉树遍历`
空间复杂度 从 O(N) 降为 O(1)
时间复杂度 O(N)

`待后续研究`
举报

相关推荐

0 条评论