1、概述
二叉树是一种特殊的树,每个父节点最多只有2个直接子孩子,每个节点也只有一个直接父节点(根节点默认无父节点)。我们实现类似下图所示的二叉树(图片来源网络):
可以看出,该树满足一般二叉树的特性:
- 包含一个树根节点
- 每个节点都最多只有2个直接子孩子
- 每个子孩子也最多只有一个父节点
- 随着树深度的增加,所能容纳的元素也是成倍增长。宽度呈指数级增长,高度增长相对较缓慢
- 等等
对二叉树一般包含如下组成:
- 树根节点
- 树的大小(通常指元素个数)
- 用于节点元素比较的函数指针域
- 其他树操作的函数指针(指向具体的操作函数)
- 等等
我们可以使用如下结构来表示
typedef struct BinaryTree
{
int size; // 大小
BTNode* root; // 树根节点
void(* destory)(void* data); // 用于释放节点数据内存的自定义函数
int (* compare)(const void* arg0, const void* arg1); // 用于比较数据大小的自定义函数
// pointers 省略部分函数指针声明..
} BTree;
同时,每个树拥有很多个节点,通常包含左右孩子指针域及数据域,对于树的节点我们可以使用如下结构来定义,:
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* left; // 左子节点
struct BinaryTreeNode* right; // 右子节点
void* data; // 存储的数据
} BTNode;
结构体不熟悉可以参考:C语言 结构体与共用体
2、实现
2.1 头文件实现
2.1.1 定义树结构、树节点结构
在BinaryTree.h中定义如下:
// 定义树节点
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* left; // 左子节点
struct BinaryTreeNode* right; // 右子节点
void* data; // 存储的数据
} BTNode;
// 定义树结构
typedef struct BinaryTree
{
int size; // 大小
BTNode* root;
void(* destory)(void* data); // 用于释放节点数据内存的自定义函数
int (* compare)(const void* arg0, const void* arg1); // 用于比较数据大小的自定义函数
// pointers
void(*BTreeInit)(struct BinaryTree* tree, void(*destory)(void* data));
void(*BTreeInitWithCompare)(struct BinaryTree* tree, int(*compare)(const void* arg0, const void* arg1));
void(*BTreeDestory)(struct BinaryTree* tree);
struct BinaryTree* (*createBTree)(void(*destory)(void* data));
int(*insertRight)(struct BinaryTree* tree, BTNode* target, const void* data);
int(*insert)(struct BinaryTree* tree, const void* data);
int(*insertLeft)(struct BinaryTree* tree, BTNode* target, const void* data);
int(*removeLeft)(struct BinaryTree* tree, BTNode* target); // 删除左子树
int(*removeRight)(struct BinaryTree* tree, BTNode* target); // 删除右子树
int(*getSize)(struct BinaryTree* tree);
BTNode* (*getRootNode)(struct BinaryTree* tree);
int(*isEndOfTree)(BTNode* tree);
int(*isLeaf)(BTNode* target);
void* (*getNodeData)(BTNode* target);
BTNode* (*getLeftChild)(BTNode* target);
BTNode* (*getRightChild)(BTNode* target);
void(*traverseTree)(BTNode* root, void(*visit)(BTNode* cur)); // 打印树root所有内容,中序遍历
void(*traverseTreeWithStack)(BTNode* root, void(*visit)(BTNode* node)); // 打印以root为树根所有内容 ,中序遍历 inorder
void(*traverseTreePreorder)(BTNode* root, void(*visit)(BTNode* node)); // 打印树root所有内容,前序遍历
void(*traverseTreePreorderWithStack)(BTNode* root, void(*visit)(BTNode* node)); // 打印树root所有内容,前序遍历
void(*traverseTreePostorder)(BTNode* root, void(*visit)(BTNode* node)); // 递归,后序遍历
void(*traverseTreePostorderWithStack)(BTNode* root, void(*visit)(BTNode* node)); // 打印以root为树根所有内容 ,后序遍历 postorder
void(*traverseWhich)(BTNode* root, void(*visit)(BTNode* node), int which) ;// 选一个遍历算法
} BTree;
2.1.2 声明相关操作函数
void BTreeInit(BTree* tree, void(*destory)(void* data)); // 对一个树进行初始化
void BTreeInitWithCompare(BTree* tree, void(*destory)(void* data), int(*compare)(const void* arg0, const void* arg1));
void BTreeDestory(BTree* tree);
BTree* createBTree(void(*destory)(void* data)); // 创建树
int insertRight(BTree* tree, BTNode* target, const void* data); // 插入到目标的右边
int insert(struct BinaryTree* tree, const void* data); // 比较值的大小来排序
int insertLeft(BTree* tree, BTNode* target, const void* data); // 插入到目标的左边
int removeLeft(BTree* tree, BTNode* target); // 删除左子树
int removeRight(BTree* tree, BTNode* target); // 删除右子树
int getSize(BTree* tree); //获取树大小
BTNode* getRootNode(BTree* tree); // 树根节点
int isEndOfTree(BTNode* target); // 是否到了树的尾端
int isLeaf(BTNode* target); // 是否为叶子节点
void* getNodeData(BTNode* target); // 节点值
BTNode* getLeftChild(BTNode* target); // 右子节点
BTNode* getRightChild(BTNode* target); // 左子节点
void traverseTree(BTNode* root, void(*visit)(BTNode* cur)); // 打印树root所有内容,中序遍历
void traverseTreeWithStack(BTNode* root, void(*visit)(BTNode* node)); // 打印以root为树根所有内容 ,中序遍历 inorder
void traverseTreePreorder(BTNode* root, void(*visit)(BTNode* node)); // 打印树root所有内容,前序遍历
void traverseTreePreorderWithStack(BTNode* root, void(*visit)(BTNode* node)); // 打印树root所有内容,前序遍历
void traverseTreePostorder(BTNode* root, void(*visit)(BTNode* node)); // 递归,后序遍历
void traverseTreePostorderWithStack(BTNode* root, void(*visit)(BTNode* node)); // 打印以root为树根所有内容 ,后序遍历 postorder
void traverseWhich(BTNode* root, void(*visit)(BTNode* node),int which); // 选一个遍历算法
2.2 实现C文件
2.2.1 创建与销毁链表
// 初始化函数指针
initRefs(BTree* tree)
{
// init
tree->BTreeInit = BTreeInit;
tree->BTreeInitWithCompare = BTreeInitWithCompare;
tree->BTreeDestory = BTreeDestory;
// modify
tree->insertRight = insertRight;
tree->insert = insert;
tree->insertLeft = insertLeft;
tree->removeLeft = removeLeft;
tree->removeRight = removeRight;
//query
tree->getSize = getSize;
tree->getRootNode = getRootNode;
tree->isEndOfTree = isEndOfTree;
tree->isLeaf = isLeaf;
tree->getNodeData = getNodeData;
tree->getLeftChild = getLeftChild;
tree->getRightChild = getRightChild;
/// traverse
tree->traverseTree = traverseTree;
tree->traverseTreeWithStack = traverseTreeWithStack;
tree->traverseTreePostorder = traverseTreePostorder;
tree->traverseTreePostorderWithStack = traverseTreePostorderWithStack;
tree->traverseTreePreorder = traverseTreePreorder;
tree->traverseTreePreorderWithStack = traverseTreePreorderWithStack;
tree->traverseWhich = traverseWhich;
}
// 对空树进行初始化
void BTreeInit(BTree* tree, void(*destory)(void* data))
{
if (tree == NULL)
{
return ;
}
tree->size = 0;
tree->destory = destory;
tree->root = NULL;
initRefs(tree);
}
// 提供比较器,用于插入时
void BTreeInitWithCompare(BTree* tree, int(*compare)(const void* arg0, const void* arg1))
{
if (tree == NULL)
{
return;
}
tree->compare = compare;
}
// 创建树
BTree* createBTree(void(*destory)(void* data))
{
BTree* tree = (BTree*)malloc(sizeof(BTree));
if (tree == NULL)
{
return NULL;
}
BTreeInit(tree, destory);
return tree;
}
// 创建树,元素可比较大小,提供比较器
BTree* createComparableBTree(void(*destory)(void* data), int(*compare)(const void* arg0, const void* arg1))
{
BTree* tree = (BTree*)malloc(sizeof(BTree));
if (tree == NULL)
{
return NULL;
}
BTreeInit(tree, destory);
BTreeInitWithCompare(tree,compare);
return tree;
}
void BTreeDestory(BTree* tree)
{
if (tree == NULL)
{
return;
}
removeLeft(tree, NULL);
memset(tree, 0, sizeof(BTree)); // 将内存重置为0
}
2.2.2 增删节点
// 插入到目标节点左边
int insertLeft(BTree* tree, BTNode* target, const void* data)
{
if (tree == NULL || data == NULL)
{
return -1;
}
BTNode *newNode, **position = NULL;
if (target == NULL) // 添加为root
{
if (tree->root != NULL) return -1;// 不重复添加
position = &tree->root;
}
else{
if (target->right != NULL) return -1;
position = &target->left;
}
if ((newNode = malloc(sizeof(BTNode))) == NULL)
{
return -1;
}
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
*position = newNode;
tree->size++;
return 1;
}
// 插入到目标节点右边
int insertRight(BTree* tree, BTNode* target, const void* data)
{
if (tree == NULL || data == NULL)
{
return -1;
}
BTNode *newNode, **position = NULL;
if (target == NULL) // 添加为root
{
if (tree->root != NULL) return -1;// 不重复添加
position = &tree->root;
}
else{
if (target->right != NULL) return -1;
position = &target->right;
}
if ((newNode = malloc(sizeof(BTNode))) == NULL)
{
return -1;
}
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
*position = newNode;
tree->size++;
return 1;
}
int insert(struct BinaryTree* tree, const void* data) // 比较值的大小来排序
{
if (tree == NULL || tree->compare == NULL)
{
return -1;
}
BTNode* newNode = NULL;
if ((newNode = (BTNode*)malloc(sizeof(BTNode))) == NULL)
{
return -1;
}
newNode->data = data;
newNode->left = NULL;
newNode->right = NULL;
BTNode* current = tree->root;
if (current == NULL) // 根为NULL
{
tree->root = newNode;
tree->size++;
return 1;
}
while (1)
{
if (tree->compare(data,current->data) >= 0) // 大于则在右子树
{
if (current->right == NULL)
{
current->right = newNode; // 添加到对应位置
break;
}
current = current->right;
}
else{ // 否则左子树
if (current->left == NULL) // 插入到当前的左child
{
current->left = newNode;
break;
}
current = current->left;
}
}
tree->size++;
return 1;
}
// 删除左子树
int removeLeft(BTree* tree, BTNode* target)
{
if (tree == NULL || tree->size == 0)
{
return -1;
}
BTNode **position; // 需要释放的子树位置
if (target == NULL) //target 为NULL,则开始删除的位置为root
{
position = &tree->root;
}
else
{
position = &target->left;
}
if (*position == NULL)
{
return 0;
}
removeLeft(tree, *position);
removeRight(tree, *position);
if (tree->destory != NULL)
{
tree->destory((*position)->data);
}
free(*position);
*position = NULL;
tree->size--;
return 1;
}
// 删除右子树
int removeRight(BTree* tree, BTNode* target)
{
if (tree == NULL || tree->size == 0)
{
return -1;
}
BTNode** position; // 需要释放的子树位置
if (target == NULL)
{
position = &tree->root;
}
else
{
position = &target->right;
}
if (*position == NULL)
{
return 0;
}
removeLeft(tree, *position);
removeRight(tree, *position);
if (tree->destory != NULL)
{
tree->destory((*position)->data);
}
free(*position);
*position = NULL;
tree->size--;
return 1;
}
2.2.3 查找与获取
// 获取树的size
int getSize(BTree* tree)
{
if (tree == NULL)
{
return -1;
}
return tree->size;
}
// 获取根节点
BTNode* getRootNode(BTree* tree)
{
if (tree == NULL)
{
return NULL;
}
return tree->root;
}
// 是否到了末尾
int isEndOfTree(BTNode* target)
{
return target == NULL;
}
// 是否为叶子节点
int isLeaf(BTNode* target)
{
if (target == NULL) // 目标节点不存在
{
return -1;
}
return target->left == NULL && target->right == NULL ? 1 : 0;
}
// 获取目标的value值
void* getNodeData(BTNode* target)
{
if (target == NULL)
{
return NULL;
}
return target->data;
}
// 获取目标的左child
BTNode* getLeftChild(BTNode* target)
{
if (target == NULL)
{
return NULL;
}
return target->left;
}
// 获取目标的右child
BTNode* getRightChild(BTNode* target)
{
if (target == NULL)
{
return NULL;
}
return target->right;
}
2.2.3 二叉树的遍历
递归形式
// 递归,打印树root所有内容,前序遍历
void traverseTreePreorder(BTNode* root, void(*visit)(BTNode* node))
{
if (root == NULL || visit == NULL)
{
return;
}
visit(root);
traverseTreePreorder(root->left, visit);
traverseTreePreorder(root->right, visit);
}
// 递归,打印树root所有内容,中序遍历
void traverseTree(BTNode* root, void(*visit)(BTNode* node))
{
if (root == NULL || visit == NULL)
{
return;
}
traverseTree(root->left,visit);
visit(root);
traverseTree(root->right,visit);
}
// 递归,打印树root所有内容,后序遍历
void traverseTreePostorder(BTNode* root, void(*visit)(BTNode* node))
{
if (root == NULL || visit == NULL) return;
traverseTreePostorder(root->left,visit);
traverseTreePostorder(root->right, visit);
visit(root);
}
非递归形式(使用辅助栈)
- 前序遍历:
// 辅助函数:一路访问left节点,并将相应的right节点入栈
void visitAlongWithLeft(BTNode* root, Stack* stack, void(*visit)(BTNode* node))
{
if (root == NULL || visit == NULL) return;
while (root != NULL)
{
visit(root); // 访问当前
if (root->right != NULL)
{
// right入栈
StackElem* elem = malloc(sizeof(StackElem));
elem->value = root->right;
pushStack(stack, elem);
}
// 下一个left
root = root->left;
}
}
// 使用栈,前序遍历
void traverseTreePreorderWithStack(BTNode* root, void(*visit)(BTNode* node)) // 打印以root为树根所有内容,前序遍历 preorder
{
if (root == NULL || visit == NULL){
return;
}
Stack* stack = initStack();
BTNode* current = root;
if (stack == NULL) return;
while (1)
{
visitAlongWithLeft(current, stack, visit);
if (isStackEmpty(stack)) break;
StackElem* elem = popStack(stack);
current = (BTNode*)elem->value; // 取出右子树,继续执行上面过程
free(elem); // 释放栈元素内存
}
free(stack); // 释放栈内存
}
- 中序遍历:
// 辅助函数:从root开始,一直将所有left入栈
void goAloneWithLeft(BTNode* root, Stack* stack)
{
if (root == NULL) return;
while (root != NULL)
{
StackElem* elem = malloc(sizeof(StackElem));
elem->value = root;
pushStack(stack, elem);
root = root->left;
}
}
// 使用辅助栈,打印以root为树根所有内容 ,中序遍历 inorder
void traverseTreeWithStack(BTNode* root, void(*visit)(BTNode* node))
{
if (root == NULL || visit == NULL) {
return;
}
Stack* stack = initStack();
BTNode* current = root;
if (stack == NULL) return;
while (1)
{
goAloneWithLeft(current, stack);
if (isStackEmpty(stack)) break;
StackElem* elem = popStack(stack);
BTNode* leftEdge = (BTNode*)elem->value; // 左边最后一个未访问的
visit(leftEdge);
current = leftEdge->right; // 遍历右子树,重复上面过程
free(elem); // 释放栈元素内存
}
free(stack); // 释放栈内存
}
- 后序遍历:
// 打印以root为树根所有内容 ,后序遍历 postorder 非递归
void traverseTreePostorderWithStack(BTNode* root, void(*visit)(BTNode* node))
{
if (root == NULL || visit == NULL)
{
return;
}
Stack* stack = initStack();
if (stack == NULL)
{
return;
}
BTNode* current = root;
while (1)
{
goAloneWithLeft(current, stack);
if (isStackEmpty(stack)) break;
StackElem* elem = peakStack(stack);
BTNode* leftEdge = (BTNode*)elem->value; // 左边最后一个
if (leftEdge->right != NULL && elem->peak <= 1) // 右元素还没有遍历
{
current = leftEdge->right; // 遍历右子树,重复上面过程
}
else
{
popStack(stack); // 出栈
visit(leftEdge);
current = NULL; // 置NULL,之后从stack取上一个left
free(elem); // 释放栈元素内存
}
}
free(stack); // 释放栈内存
}
3、实现辅助栈
3.1 栈头文件
#pragma once
#include<stdlib.h>
#include<stdio.h>
// 栈存储元素
typedef struct StackElem_
{
void* value;
struct StackElem_* next;
struct StackElem_* prev;
int peak; // peak的次数
}StackElem;
// 栈结构
typedef struct Stack_
{
int size;
StackElem* top;
} Stack;
// 初始化空栈
Stack* initStack();
// 压栈
void pushStack(Stack* stack, StackElem* elem);
// 弹出栈
StackElem* popStack(Stack* stack);
// 获取栈顶值而不弹出
StackElem* peakStack(Stack* stack);
void showAll(Stack* stack);
// 是否为空栈
int isStackEmpty(Stack* stack);
3.2 栈实现
#include"link_stack.h"
Stack* initStack()
{
Stack* stack = malloc(sizeof(Stack));
stack->size = 0;
stack->top = NULL;
return stack;
}
// 压栈
void pushStack(Stack* stack, StackElem* elem)
{
if (stack == NULL || elem == NULL)
{
return;
}
elem->peak = 0;
if (stack->top == NULL)
{
stack->top = elem;
elem->prev = NULL;
elem->next = NULL;
}
else
{
stack->top->next = elem;
elem->prev = stack->top;
elem->next = NULL;
stack->top = elem; // top后移
}
stack->size++;
//printf("\nsize=%d\n", stack->size);
}
// 弹出栈
StackElem* popStack(Stack* stack)
{
if (stack->size==0)
{
return NULL;
}
StackElem* elem = stack->top;
stack->top = stack->top->prev;
if (stack->top != NULL)
{
stack->top->next;
}
stack->size--;
return elem;
}
// 获取栈顶的值,而弹出栈
StackElem* peakStack(Stack* stack)
{
if (stack->size == 0)
{
return NULL;
}
stack->top->peak += 1;
return stack->top;
}
void showAll(Stack* stack)
{
if (stack != NULL)
{
StackElem* current = stack->top;
while (current != NULL)
{
printf("current is %d\n", *(int*)(current->value));
current = current->prev;
}
}
}
// 返回非0为空
int isStackEmpty(Stack* stack)
{
return stack->size == 0;
}
4、使用
#include"BinaryTree.h"
#include"Log.h"
#include"link_stack.h"
// 比较函数
int compare(int* pa, int* pb)
{
int a = *pa;
int b = *pb;
return (a > b) ? 1 : ((a == b) ? 0 : -1);
}
// 打印
void printNode(BTNode* node)
{
if (node == NULL || node->data == NULL)
{
return;
}
printf("current data is %d\n", *(int*)(node->data));
}
void main()
{
BTree* tree = createComparableBTree(NULL,compare);
printf("%#x\n", &tree->root);
int a = 1, b = 2, c = 3,d=-1,e=-2,f=0,h=6,k=-6;
tree->insert(tree, &a);
tree->insert(tree, &d);
tree->insert(tree, &c);
tree->insert(tree, &b);
tree->insert(tree, &e);
tree->insert(tree, &f);
tree->insert(tree, &h);
tree->insert(tree, &k);
//printf("%d\n", *(int*)(tree->root->data));
//tree->traverseTree(tree->root,printNode);
//tree->traverseTreeWithStack(tree->root, printNode);
//tree->traverseTreePreorder(tree->root,printNode);
//tree->traverseTreePreorderWithStack(tree->root, printNode);
//tree->traverseTreePostorder(tree->root, printNode);
tree->traverseTreePostorderWithStack(tree->root, printNode);
system("pause");
}
测试traverseTreePostorderWithStack输出:
current data is -6
current data is -2
current data is 0
current data is -1
current data is 2
current data is 6
current data is 3
current data is 1