二叉通用树C语言实现---双亲孩子法

还是国嵌之前数据结构和算法视频里面唐老师的代码,最近刷二叉树的相关题目,整好拿来用用,先贴源代码,顺便复习一下,老师的代码真的很棒!后边借助老师之前的链表以及栈的实现,非递归实现二叉树的前序遍历、中序遍历、后续遍历、以及层次遍历-全部用栈实现。

目标实现如下二叉树,并且打印结果,

/举例
/************************************
              A
            /    \
           B     C
         /   \    /  \
        D   E F   G
      /   \  / 
     H   I J
*************************************/

先贴代码:

BTree.c

#include <stdio.h>
#include <malloc.h>
#include "BTree.h"

// 定义二叉树根结点结构体
typedef struct _tag_BTree TBTree;
struct _tag_BTree
{
    int count;                // 记录二叉树结点个数
    BTreeNode* root;          // 二叉树结点指针结构体,指向树结点根节点
};

// 创建二叉树
BTree* BTree_Create() // O(1)
{
    // 定义二叉树结点结构体变量,并申请内存
    TBTree* ret = (TBTree*)malloc(sizeof(TBTree));

    if( ret != NULL )
    {
        ret->count = 0;
        ret->root = NULL;
    }
    
    return ret;
}

// 销毁二叉树
void BTree_Destroy(BTree* tree) // O(1)
{
    free(tree);       // 释放内存
}

// 清空二叉树
void BTree_Clear(BTree* tree) // O(1)
{

    TBTree* btree = (TBTree*)tree;

    if( btree != NULL )
    {
        btree->count = 0;
        btree->root = NULL;
    }
}

// 在二叉树指定位置pos插入结点node
// pos:定位的方向,二进制:0表示左,1表示右
// count:定位次数,移动指针次数
// flag:插入方向 BT_LEFT or BT_RIGHT
int BTree_Insert(BTree* tree, BTreeNode* node, BTPos pos, int count, int flag) // O(n) 
{

    TBTree* btree = (TBTree*)tree;    
    // 入口参数合法性检查
    int ret = (btree != NULL) && (node != NULL) && ((flag == BT_LEFT) || (flag == BT_RIGHT));
    int bit = 0;

    if( ret )
    {

        BTreeNode* parent = NULL;
    	// 定义二叉树左右指针结构体变量,存放当前结点地址
        BTreeNode* current = btree->root;
        // 初始化插入结点的左右指针地址,默认为NULL
        node->left = NULL;
        node->right = NULL;
        // 开始定位  定位次数不为零,插入的位置不是根结点
        while( (count > 0) && (current != NULL) )
        {
            // 取定位方向参数最右边bit位用于判断左右
            bit = pos & 1;
            pos = pos >> 1;
            // 临时变量更新当前指针,保存插入结点位置的双亲指针
            parent = current;
            // 左边,向左移动指针
            if( bit == BT_LEFT )
            {
                current = current->left;        // 将当前结点指针指向左边子结点指针
            }
            // 右边,向右移动指针
            else if( bit == BT_RIGHT )
            {
                current = current->right;       // 将当前结点指针指向右边子结点指针
            }
            // 定位次数减1
            count--;
        }
        // 定位完成后,如果该位置节点已经存在,判断待插入结点的插入位置flag表示插入该节点后,原位置的节点在该节点的左边还是右边
        if( flag == BT_LEFT )
        {
            node->left = current;           // 将带插入结点的左指针指向当前结点
        }
        else if( flag == BT_RIGHT )
        {
            node->right = current;          // 将待插入结点的右指针指向当前结点
        }
        
        // 当前结点指针不为空,即不是根结点
        if( parent != NULL )
        {

            if( bit == BT_LEFT )
            {
                parent->left = node;         // 将插入结点位置的双亲指针的左指针指向待插入结点
            }
            else if( bit == BT_RIGHT )
            {
                parent->right = node;        // 将插入结点位置的双亲指针的右指针指向待插入结点
            }
        }
        // 插入的是首结点,即根结点
        else
        {
            btree->root = node;
        }
        // 二叉树结点个数加1
        btree->count++;
    }
    
    return ret;
}

// 显示递归函数
static void recursive_display(BTreeNode* node, BTree_Printf* pFunc, int format, int gap, char div) // O(n)
{
    int i = 0;
    // 合法性检查OK
    if( (node != NULL) && (pFunc != NULL) )
    {
    	// 打印格式符
        for(i=0; i<format; i++)
        {
            printf("%c", div);
        }
        // 打印内容
        pFunc(node);
        
        printf("\n");
        // 存在左子树结点或存在右子树结点
        if( (node->left != NULL) || (node->right != NULL) )
        {
 
            recursive_display(node->left, pFunc, format + gap, gap, div);      // 调用递归函数打印左子树结点
            recursive_display(node->right, pFunc, format + gap, gap, div);     // 调用递归函数打印右子树结点
        }
    }
    // 根结点为空
    else
    {    	  
    	  // 打印格式符
        for(i=0; i<format; i++)
        {
            printf("%c", div);
        }
        printf("\n");
    }
}


// 显示二叉树
void BTree_Display(BTree* tree, BTree_Printf* pFunc, int gap, char div) // O(n)
{
	  // 定义二叉树结点结构体变量,强制转换入口参数
    TBTree* btree = (TBTree*)tree;
    // 合法性检查OK,调用显示递归函数
    if( btree != NULL )
    {
        recursive_display(btree->root, pFunc, 0, gap, div);
    }
}

// 求二叉树结点子树结点个数
static int recursive_count(BTreeNode* root) // O(n)
{
    int ret = 0;
    // 合法性检查ok
    if( root != NULL )
    {
        ret = recursive_count(root->left) + 1 + recursive_count(root->right);    // 调用递归函数计算个数
    }
    // 返回个数
    return ret;
}



int BTree_Count(BTree* tree)
{

    TBTree* btree = (TBTree*)tree;
    int ret = 0;    
    // 入口参数合法性检查ok,调用递归函数求二叉树高度
    if( btree != NULL )
    {
        ret = recursive_count(btree->root);
    }
    // 返回二叉树高度
    return ret;

}

// 删除指定位置的结点
BTreeNode* BTree_Delete(BTree* tree, BTPos pos, int count) // O(n)
{
    TBTree* btree = (TBTree*)tree;
    BTreeNode* ret = NULL; 
    int bit = 0;    

    if( btree != NULL )
    {
    	  // 定义二叉树左右指针结构体临时变量
        BTreeNode* parent = NULL;
    	  // 定义二叉树左右指针结构体变量,存放当前结点地址
        BTreeNode* current = btree->root;        
        // 开始定位  定位次数不为零,删除的位置不是根结点
        while( (count > 0) && (current != NULL) )
        {
            // 取定位方向参数最右边bit位用于判断左右
            bit = pos & 1;
            pos = pos >> 1;
            
            // 临时变量更新当前指针,保存删除结点位置的双亲指针
            parent = current;            
            // 左边,向左移动指针
            if( bit == BT_LEFT )
            {
                current = current->left;         // 将删除结点位置的双亲指针的左指针指向待删除结点
            }
            // 右边,向右移动指针
            else if( bit == BT_RIGHT )
            {
                current = current->right;        // 将删除结点位置的双亲指针的右指针指向待删除结点
            }
            // 定位次数减1             
            count--;
        }        
        // 当前结点指针不为空,即不是根结点
        if( parent != NULL )
        {
            // 左边
            if( bit == BT_LEFT )
            {
                parent->left = NULL;         // 将结点左子树位置指向空指针,即删除左结点
            }
            // 右边
            else if( bit == BT_RIGHT )
            {
                parent->right = NULL;        // 将结点右子树位置指向空指针,即删除右结点
            }
        }
        // 删除的是首结点,即根结点
        else
        {
            btree->root = NULL;              // 将根结点指向空指针,即删除所有结点
        }
        // 返回删除元素结点
        ret = current;
        // 更新二叉树结点个数,结点个数减去删除的结点个数
        btree->count = btree->count - recursive_count(ret);
    }
    
    return ret;
}

// 获取指定位置的结点
//如果获取的节点位置为空怎么办 
BTreeNode* BTree_Get(BTree* tree, BTPos pos, int count) // O(n)
{
    // 定义二叉树结点结构体变量,强制转换入口参数
    TBTree* btree = (TBTree*)tree;
    // 定义返回变量
    BTreeNode* ret = NULL; 
    int bit = 0;
    int i = 0;
    
    // 入口参数合法性检查ok
    if( btree != NULL )
    {
    	// 定义二叉树左右指针结构体变量,存放当前结点地址
        BTreeNode* current = btree->root;        
        // 开始定位  定位次数不为零,删除的位置不是根结点
        while( (count > 0) && (current != NULL) )
        {
            // 取定位方向参数最右边bit位用于判断左右
            bit = pos & 1;
            pos = pos >> 1;
            
            // 左边,向左移动指针
            if( bit == BT_LEFT )
            {
                current = current->left;
            }
            // 右边,向右移动指针
            else if( bit == BT_RIGHT )
            {
                current = current->right;
            }
            //printf("the tree node is %d\n", i++);
            // 定位次数减1   
            count--;
        }
        
        ret = current;
   
    }
    
    return ret;
}

// 获取根结点
BTreeNode* BTree_Root(BTree* tree) // O(1)
{
    // 定义二叉树结点结构体变量,强制转换入口参数
    TBTree* btree = (TBTree*)tree;
    // 定义返回变量
    BTreeNode* ret = NULL;
    // 入口参数合法性检查ok,返回根结点地址
    if( btree != NULL )
    {
        ret = btree->root;
    }
    
    return ret;
}

// 求二叉树高度递归函数
static int recursive_height(BTreeNode* root) // O(n)
{
    int ret = 0;
    if( root != NULL )
    {
        int lh = recursive_height(root->left);       // 求左子树高度
        int rh = recursive_height(root->right);      // 求右子树高度
        // 求左右子树高度最大值
        ret = ((lh > rh) ? lh : rh) + 1;
    }
    // 返回二叉树高度
    return ret;
}

// 获取二叉树高度
int BTree_Height(BTree* tree) // O(n)
{
    // 定义二叉树结点结构体变量,强制转换入口参数
    TBTree* btree = (TBTree*)tree;
    int ret = 0;    

    if( btree != NULL )
    {
        ret = recursive_height(btree->root);
    }
    // 返回二叉树高度
    return ret;
}

// 求二叉树度递归函数,最大度为2
static int recursive_degree(BTreeNode* root) // O(n)
{

    int ret = 0;    

    if( root != NULL )
    {
    	 // 左子树结点不为空,度加1
        if( root->left != NULL )
        {
            ret++;
        }        
    	 // 右子树结点不为空,度加1
        if( root->right != NULL )
        {
            ret++;
        }
        // 度为1,调用递归函数求其他结点度
        if( ret == 1 )
        {
            int ld = recursive_degree(root->left);       // 求左子树结点的度
            int rd = recursive_degree(root->right);      // 求右子树结点的度
            // 求左子树结点度的最大值
            if( ret < ld )
            {
                ret = ld;
            }            
            // 求右子树结点度的最大值
            if( ret < rd )
            {
                ret = rd;
            }
        }
    }

    return ret;
}


// 获取二叉树度
int BTree_Degree(BTree* tree) // O(n)
{
    TBTree* btree = (TBTree*)tree;
    int ret = 0;    

    if( btree != NULL )
    {
        ret = recursive_degree(btree->root);
    }
    // 返回二叉树的度
    return ret;
}

BTree.h

#ifndef __BTREE_H_
#define __BTREE_H_
 
#define BT_LEFT 0            //  左边
#define BT_RIGHT 1           //  右边


// 定义新数据类型,用于封装函数
typedef void BTree;
typedef unsigned long long BTPos;

// 定义二叉树左右指针结构体
typedef struct _tag_BTreeNode BTreeNode;
struct _tag_BTreeNode
{
    BTreeNode* left;         // 二叉树左结点指针
    BTreeNode* right;        // 二叉树右结点指针
};

typedef void (BTree_Printf)(BTreeNode*);

 
void BTree_Destroy(BTree* tree);

BTree* BTree_Create();

void BTree_Clear(BTree* tree);

int BTree_Insert(BTree* tree, BTreeNode* node, BTPos pos, int count, int flag);

void BTree_Display(BTree* tree, BTree_Printf* pFunc, int gap, char div);

BTreeNode* BTree_Delete(BTree* tree, BTPos pos, int count);

BTreeNode* BTree_Get(BTree* tree, BTPos pos, int count);

BTreeNode* BTree_Root(BTree* tree);

int BTree_Height(BTree* tree);

int BTree_Degree(BTree* tree);

int BTree_Count(BTree* tree);

 
#endif  

测试demo :main.c

#include <stdio.h>
#include <stdlib.h>
#include "BTree.h"
 
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
// 定义二叉树数据域结构体
struct Node
{
    BTreeNode header;
    char v;
};
// 定义打印内容函数
void printf_data(BTreeNode* node)
{
    if( node != NULL )
    {
        printf("%c", ((struct Node*)node)->v);
    }
}
 
int main(int argc, char *argv[])
{
	  // 创建二叉树
    BTree* tree = BTree_Create();
    // 定义要插入结点元素
    struct Node n1 = {{NULL, NULL}, 'A'};
    struct Node n2 = {{NULL, NULL}, 'B'};
    struct Node n3 = {{NULL, NULL}, 'C'};
    struct Node n4 = {{NULL, NULL}, 'D'};
    struct Node n5 = {{NULL, NULL}, 'E'};
    struct Node n6 = {{NULL, NULL}, 'F'};
	struct Node n7 = {{NULL, NULL}, 'G'};
	struct Node n8 = {{NULL, NULL}, 'H'};
	struct Node n9 = {{NULL, NULL}, 'I'};
	struct Node n10 = {{NULL, NULL}, 'J'};  
    // 插入结点元素
	// 在二叉树指定位置pos插入结点node
	// pos:定位的方向,二进制:0表示左,1表示右
	// count:定位次数,移动指针次数
	// flag:插入方向 BT_LEFT or BT_RIGHT
	
    BTree_Insert(tree, (BTreeNode*)&n1, 0x00, 0, 0);//A 根节点 
    BTree_Insert(tree, (BTreeNode*)&n2, 0x00, 1, 0);//B
    BTree_Insert(tree, (BTreeNode*)&n3, 0x01, 1, 0);//C
    BTree_Insert(tree, (BTreeNode*)&n4, 0x00, 2, 0);//D
    BTree_Insert(tree, (BTreeNode*)&n5, 0x02, 2, 0);//E
    BTree_Insert(tree, (BTreeNode*)&n6, 0x01, 2, 0);//F
    BTree_Insert(tree, (BTreeNode*)&n7, 0x03, 2, 0);//G
    BTree_Insert(tree, (BTreeNode*)&n8, 0x00, 3, 0);//H
    BTree_Insert(tree, (BTreeNode*)&n9, 0x04, 3, 0);//I
    BTree_Insert(tree, (BTreeNode*)&n10, 0x02, 3, 0);//J
    // 打印相应提示内容
    printf("Height: %d\n", BTree_Height(tree));
    printf("Degree: %d\n", BTree_Degree(tree));
    printf("Count: %d\n", BTree_Count(tree));
    if((struct Node*)BTree_Get(tree, 0x02, 2) != NULL)
    	printf("Position At (0x02, 2): %c\n", ((struct Node*)BTree_Get(tree, 0x02, 2))->v);
    printf("Full Tree: \n");
    // 显示二叉树
    BTree_Display(tree, printf_data, 4, '-');
    // 测试删除结点功能
    BTree_Delete(tree, 0x00, 1);   
    // 打印相应提示内容
    printf("After Delete B: \n");
    printf("Height: %d\n", BTree_Height(tree));
    printf("Degree: %d\n", BTree_Degree(tree));
    printf("Count: %d\n", BTree_Count(tree));
    printf("Full Tree: \n");    
    // 显示删除结点后的二叉树
    BTree_Display(tree, printf_data, 4, '-');
    
    // 测试清空二叉树功能
    BTree_Clear(tree);    
    // 打印相应提示内容
    printf("After Clear: \n");
    printf("Height: %d\n", BTree_Height(tree));
    printf("Degree: %d\n", BTree_Degree(tree));
    printf("Count: %d\n", BTree_Count(tree));    
    // 显示清空后的二叉树
    BTree_Display(tree, printf_data, 4, '-');
    // 销毁二叉树
    BTree_Destroy(tree);
    
	return 0;
}

部分测试运行结果:

/************************************
              A
            /    \
           B     C
         /   \    /  \
        D   E F   G
      /   \  / 
     H   I J
*************************************/

二叉树里面好多接口函数用到了递归,递归本质其实就是一个栈结构,用递归能实现的,用栈都可以实现。该代码精髓在节点插入和节点删除的地方。考虑的比较全面,多多仔细推敲代码能收获不少。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值