还是国嵌之前数据结构和算法视频里面唐老师的代码,最近刷二叉树的相关题目,整好拿来用用,先贴源代码,顺便复习一下,老师的代码真的很棒!后边借助老师之前的链表以及栈的实现,非递归实现二叉树的前序遍历、中序遍历、后续遍历、以及层次遍历-全部用栈实现。
目标实现如下二叉树,并且打印结果,
/举例
/************************************
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
*************************************/
二叉树里面好多接口函数用到了递归,递归本质其实就是一个栈结构,用递归能实现的,用栈都可以实现。该代码精髓在节点插入和节点删除的地方。考虑的比较全面,多多仔细推敲代码能收获不少。