笔试二叉树

103 阅读4分钟

1、基本特征

A、表达树形结构的最简模型, 每个节点最多有两个子节点
B、单根, 每个子节点有且仅有一个父节点, 整棵树只有一个根节点
C、具有递归结构的特征, 用递归的方法处理, 可以简化算法

2、基本操作: 生成、遍历

按照特定的规则生成或遍历, 能得到一个特定的结构

3、实现要点

A、由父及子的生成方式

B、三种遍历序

(a)前序遍历: 处理节点自己的数据->处理左节点->处理右节点

(b)中序遍历: 处理左节点->处理节点自己的数据->处理右节点

(c)后序遍历: 处理左节点->处理右节点->处理节点自己的数据

范例:

有序二叉树(二叉搜索树)

在树中的任何一个节点, 左子节点的值 < 节点值 < 右子节点的值

// .h
// 有序二叉树(二叉搜索树)
#ifndef _BT_H
#define _BT_H

#include <sys/types.h>

/*

中序二叉树
50,70,20,60,40,30,10,90,80

            50
          _/  \_
         /      \
        20      70
       /  \    /  \
      10  40  60  90
          /       /
         30      80

中序遍历: 10,20,30,40,50,60,70,80,90
前序遍历: 50,20,10,40,30,70,60,90,80
后续遍历: 10,30,40,20,60,80,90,70,50

*/

// 节点
typedef struct BsTreeNode
{
    int data;  // 数据
    struct BsTreeNode* left;  // 左子树
    struct BsTreeNode* right;  // 右子树
} BSTREE_NODE;

// 二叉树
typedef struct BsTree
{
    BSTREE_NODE* root;  // 根节点
    size_t size;  // 数量
} BSTREE;

// 初始化为空树
void bstree_init(BSTREE* bstree);

// 释放剩余节点并恢复到初始状态
void bstree_deinit(BSTREE* bstree);

// 插入
void bstree_insert(BSTREE* bstree, int data);

// 删除
int bstree_erase(BSTREE* bstree, int data);

// 删除所有匹配数据
void bstree_remove(BSTREE* bstree, int data);

// 清空
void bstree_clear(BSTREE* bstree);

// 更新
void bstree_update(BSTREE* bstree, int old, int new);

// 判断是否存在
int bstree_exist(BSTREE* bstree, int data);

// 中序遍历
void bstree_travel(BSTREE* bstree);

// 数量
size_t bstree_size(BSTREE* bstree);

// 高度
size_t bstree_height(BSTREE* bstree);

#endif

// .c
#include <stdio.h>
#include <stdlib.h>
#include "cbtree.h"

static BSTREE_NODE* create_node(int data)
{
    BSTREE_NODE* node = (BSTREE_NODE*)malloc(sizeof(BSTREE_NODE));
    node->data = data;
    node->left = NULL;
    node->right = NULL;
    return node;
}

static void destroy_node(BSTREE_NODE* node)
{
    free(node);
}

// -----------------------递归形式的内部接口--------------------------

// 清空以参数节点为根的子树
static void clear(BSTREE_NODE** tree)
{
    if (*tree) {
        clear(&(*tree)->left);
        clear(&(*tree)->right);
        destroy_node(*tree);
        *tree = NULL;
    }
}

static void insert(BSTREE_NODE* node, BSTREE_NODE** tree)
{
    if (!*tree) {
        *tree = node;
    }
    else if (node) {
        if (node->data < (*tree)->data) {
            // 插入左子树
            insert(node, &(*tree)->left);
        }
        else {
            // 插入右子树
            insert(node, &(*tree)->right);
        }
    }
}

// 返回以参数tree的目标所指向的节点为根的子树中,
// 数值与参数data相匹配的节点的父节点中,指向该节点的指针型成员变量的地址
static BSTREE_NODE** find(int data, BSTREE_NODE** tree)
{
    if (! *tree) {
        return tree;
    }
    else {
        if (data == (*tree)->data) {
            return tree;
        }
        else {
            if (data < (*tree)->data) {
                return find(data, &(*tree)->left);
            }
            else {
                return find(data, &(*tree)->right);
            }
        }
    }
}

static void travel(BSTREE_NODE* tree)
{
    if (tree) {
        travel(tree->left);
        printf("%d ", tree->data);
        travel(tree->right);
    }
}

static size_t height(BSTREE_NODE* tree)
{
    if (tree) {
        size_t lh = height(tree->left);
        size_t rh = height(tree->right);
        return (lh > rh ? lh : rh) + 1;
    }
    return 0;
}

// 初始化为空树
void bstree_init(BSTREE* bstree)
{
    bstree->root = NULL;
    bstree->size = 0;
}

// 释放剩余节点并恢复到初始状态
void bstree_deinit(BSTREE* bstree)
{
    clear(&bstree->root);
    bstree->size = 0;
}

// 插入
void bstree_insert(BSTREE* bstree, int data)
{
    insert(create_node(data), &bstree->root);
    ++bstree->size;
}

// 删除
int bstree_erase(BSTREE* bstree, int data)
{
    // 删除节点前, 要把左子树插入右子树,然后把右子树提升到当前节点
    BSTREE_NODE** node = find(data, &bstree->root);

    if (*node) {
        // 将匹配节点的左子树插入右子树
        insert((*node)->left, &(*node)->right);

        BSTREE_NODE* temp = *node;
        // 用匹配节点的右子树的根节点取代匹配节点
        *node = (*node)->right;
        // 删除匹配节点
        destroy_node(temp);
        --bstree->size;
        return 1;
    }

    return 0;
}

// 删除所有匹配数据
void bstree_remove(BSTREE* bstree, int data)
{
    while (bstree_erase(bstree, data)); 
}

// 清空
void bstree_clear(BSTREE* bstree)
{
    bstree_deinit(bstree);
}

// 更新
void bstree_update(BSTREE* bstree, int old, int new)
{
    while (bstree_erase(bstree, old)) {
        bstree_insert(bstree, new);
    }
}

// 判断是否存在
int bstree_exist(BSTREE* bstree, int data)
{
    return *find(data, &bstree->root) != NULL;
}

// 中序遍历
void bstree_travel(BSTREE* bstree)
{
    travel(bstree->root);
    printf("\n");
}

// 数量
size_t bstree_size(BSTREE* bstree)
{
    return bstree->size;
}

// 高度
size_t bstree_height(BSTREE* bstree)
{
    return height(bstree->root);
}

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

int main(void)
{
    BSTREE tree;

    bstree_init(&tree);

    bstree_insert(&tree, 50);
    bstree_insert(&tree, 70);
    bstree_insert(&tree, 20);
    bstree_insert(&tree, 60);
    bstree_insert(&tree, 40);
    bstree_insert(&tree, 30);
    bstree_insert(&tree, 10);
    bstree_insert(&tree, 90);
    bstree_insert(&tree, 80);

    printf("%zu, %zu \n", bstree_size(&tree), bstree_height(&tree));

    bstree_travel(&tree);

    bstree_erase(&tree, 60);
    bstree_travel(&tree);

    bstree_insert(&tree, 50);
    bstree_insert(&tree, 50);
    bstree_travel(&tree);
    bstree_remove(&tree, 50);
    bstree_travel(&tree);

    bstree_insert(&tree, 40);
    bstree_insert(&tree, 40);
    bstree_travel(&tree);
    bstree_update(&tree, 40, 85);
    bstree_travel(&tree);

    printf("%d, %d\n", bstree_exist(&tree, 40), bstree_exist(&tree, 85));

    bstree_deinit(&tree);

    return 0;
}

/*
Output:

9, 4 
10 20 30 40 50 60 70 80 90 
10 20 30 40 50 70 80 90 
10 20 30 40 50 50 50 70 80 90 
10 20 30 40 70 80 90 
10 20 30 40 40 40 70 80 90 
10 20 30 70 80 85 85 85 90 
0, 1

*/