##binarytree.h
#include<stdio.h>
#include<windows.h>
#include<assert.h>
typedef int BTDataType;
typedef struct BinaryTreeNode
{
struct BinaryTreeNode* _left; //左孩子
struct BinaryTreeNode* _right; //右孩子
BTDataType _data; //数据域
}BTNode;//树的每个节点
#include"stack.h"
#include"queue.h"
BTNode *BuyNewNode(BTDataType x)//创建新节点
{
BTNode *newnode = (BTNode *)malloc(sizeof(BTNode));
assert(newnode);
newnode->_data = x;
newnode->_left = NULL;
newnode->_right = NULL;
return newnode;
}
BTNode *BinaryTreeCreateByPrev(int *a, int *index, int invalid)//先序创建二叉树
{
//思路:
//从数组头开始读取数据,遇到合法值,创建新节点,紧接着递归的创建左孩子和右孩子,V L R
//遇到非法值时直接return NULL,创建完左右孩子return 当前节点的地址
assert((*index) >= 0);
if (a[*index] == invalid)
{
return NULL;
}
//到这一步时,可以判断数组的当前位置值为合法的,开始创建新节点
BTNode *root = BuyNewNode(a[*index]);
++(*index);//数组下标后移
root->_left = BinaryTreeCreateByPrev(a, index, invalid);//递归:创建左孩子
++(*index);//数组下标后移
root->_right = BinaryTreeCreateByPrev(a, index, invalid);//递归:创建右孩子
//左右孩子都创建好,或者因非法return NULL
//返回上层递归
return root;
}
void BTreePrevOrder(BTNode *root)//先序,递归遍历二叉树 V L R
{
//子问题:每个节点的左右孩子都要保证以R L T方式遍历
//递归出口:抵达叶子节点,在向下遍历为空时
if (root == NULL)
{
return;
}
//到这里说明还该处有节点,依照 V L R依次遍历,每个节点都是如此
printf("%2d", root->_data);
BTreePrevOrder(root->_left);
BTreePrevOrder(root->_right);
}
void BTreeInOrder(BTNode* root)//中序遍历二叉树
{
//子问题:每个节点的左右孩子必须按照L V R顺序遍历
//递归出口:抵达叶子节点,在向下遍历为空时
if (root == NULL)
{
return;
}
BTreeInOrder(root->_left);
printf("%2d", root->_data);
BTreeInOrder(root->_right);
}
void BTreePostOrder(BTNode* root)//后序遍历二叉树
{
//子问题:每个节点的左右孩子都必须按照 L R V顺序遍历
//递归出口:抵达叶子节点,在向下遍历为空时
if (root == NULL)
{
return;
}
BTreePostOrder(root->_left);
BTreePostOrder(root->_right);
printf("%2d", root->_data);
}
size_t BTreeSize(BTNode* root)//二叉树的总结点数
{
//子问题:一个树的节点个数都可以分解成 1 + 其左子树的节点个数 + 其右节点的节点个数
if (root == NULL)
{
return 0;
}
return (1 + BTreeSize(root->_left) + BTreeSize(root->_right));
}
size_t BTreeLeafSize(BTNode* root)//二叉树的叶子节点数
{
//如果树为空,返回0;
//如果该节点为叶子节点,返回1
//子问题:如果该节点不是叶子节点(有左右子树),返回其左子树的叶子节点个数 + 右子树节点个数
if (root == NULL)
{
return 0;
}
if (root->_left == NULL&&root->_right == NULL)
{
return 1;
}
return BTreeLeafSize(root->_left) + BTreeLeafSize(root->_right);
}
size_t BTreeKLevelSize(BTNode* root, size_t k)//二叉树第k层节点数
{
//子问题:如果当前层不是我们要查的,则k--,
//且改为查其左子树的第k层的节点数+其右节点的第k层的节点数
//递归出口:k==1,此时一定是我们要查的层数,返回当前节点数
assert(k);//k至少为1
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
k--;
return BTreeKLevelSize(root->_left, k) + BTreeKLevelSize(root->_right, k);
}
size_t BTreeDepth(BTNode* root)//二叉树的深度
{
//子问题:从根结点开始,如果根节点有左右子树,那么他的深度为1+(左子树深度||右子树深度(取大值))
//递归出口:如果当前节点已经是最深的节点,则返回0;
if (root == NULL)
{
return 0;
}
size_t left = BTreeDepth(root->_left);
size_t right = BTreeDepth(root->_right);
return 1 + (left > right ? left : right);
}
void BTreeLevelOrder(BTNode* root)//广度遍历二叉树
{
//思路:层序遍历需要借助一个队列完成,当根节点不为空时,将根节点指针入队,为空直接返回。
//接着进入循环:如果队头节点有左节点或者右节点,则将他们的指针入队,然后对队头元素指针出队并打印,
//直至队列为空
Queue q;
QueueInit(&q);
if (root == NULL)
{
return;
}
QueuePush(&q, root);
while (QueueEmpty(&q))
{
BTNode *front = QueueFront(&q);
if (front->_left != NULL)
{
QueuePush(&q, front->_left);
}
if (front->_right != NULL)
{
QueuePush(&q, front->_right);
}
printf("%2d", front->_data);
QueuePop(&q);
free(front);
}
}
BTNode* BTreeFind(BTNode* root, BTDataType x)//二叉树的查找
{
//思路:若树为空树,则return NULL
// 如果找到,return x的指针
// 递归遍历左子树和右子树继续找
if (root == NULL)
{
return NULL;
}
if (root->_data == x)
{
return root;
}
BTNode *ret = NULL;
if (root->_left)
{
ret = BTreeFind(root->_left, x);
if (ret)
{
return ret;
}
}
if (root->_right)
{
ret = BTreeFind(root->_right, x);
if (ret)
return ret;
}
return NULL;
}
int IsCompleteBTree(BTNode* root)//判断一棵二叉树是否是完全二叉树
{
//思路:完全二叉树的特性是前n-1层是满的,最后第n层的前k个是连续不间断的,后面不足无所谓。
//那么就可以借助层序遍历,有左右子树就入队,没有对应的子树也入一个NULL进去,当第一次
//遍历至NULL时,后面队列里的所有成员必须全是NULL,否则就不是完全二叉树(不满足连续)
Queue q;
QueueInit(&q);
if (root == NULL)
{
return 0;
}
QueuePush(&q, root);
while (QueueFront(&q) != NULL)
{
BTNode *front = QueueFront(&q);
QueuePush(&q, front->_left);
QueuePush(&q, front->_right);
QueuePop(&q);
free(front);
}
if (QueueEmpty(&q) == 0)
{
return 1;
}
else
{
while (QueueEmpty(&q))
{
if (QueueFront(&q) != NULL)
{
return 0;
}
QueuePop(&q);
}
return 1;
}
}
void BTreePrevOrderNonR(BTNode* root)//前序非递归遍历二叉树
{
//前序非递归遍历二叉树
//思路:不用递归,可以用运营一个栈来模拟递归
if (root == NULL)
{
return;
}
Stack s;
StackInit(&s);
BTNode *cur = root;
while (cur || StackEmpty(&s))//cur不为空说明当前节点还可以遍历
{ //stack不为空说明栈内元素可能还有孩子没有被遍历
while (cur)
{
printf("%d ", cur->_data);
StackPush(&s, cur);
cur = cur->_left;
}
//运行到这说明已经到达了最左节点,该遍历该节点的右子树了
BTNode *top = StackTop(&s);
cur = top->_right;
//此处用cur记录了top的右节点,要及时出栈,否则如果有top有右子树,入栈后,就无法将top再出栈了
StackPop(&s);
}
}
void BTreeInOrderNonR(BTNode* root)//中序非递归遍历二叉树
{
//思路与前序非递归类似,遇到一个节点时,先入栈,然后一直进入左子树
Stack s;
StackInit(&s);
BTNode *cur = root;
while (cur || StackEmpty(&s))//cur不为空说明当前节点还可以遍历
{ //stack不为空说明栈内元素可能还有孩子没有被遍历
while (cur)
{
StackPush(&s, cur);
cur = cur->_left;
}
//运行到这儿说明已经到达最左节点,该输出该节点了
BTNode *top = StackTop(&s);
printf("%d ", top->_data);
cur = top->_right;//这里说明左孩子,中根节点已经遍历完毕,该右孩子遍历了
StackPop(&s);
}
}
void BTreePostOrderNonR(BTNode* root)//后序非递归遍历二叉树
{
//后序非递归会比前序中序复杂一点,复杂的点就在于它的遍历顺序是左右中,
//当把左孩子遍历完,该遍历右孩子了,这里cur会来到中根节点,当右孩子遍历完,cur又来到
//中根节点,如何判断是否已经遍历右孩子?是后序遍历的关键。
Stack s;
StackInit(&s);
BTNode *cur = root;
BTNode *last = NULL;//新定义一个last记录右孩子是否遍历过,遍历过则将top->_right赋给last
while (cur || StackEmpty(&s))
{
while (cur)
{
StackPush(&s, cur);
cur = cur->_left;
}
BTNode *top = StackTop(&s);
//如果此时发现top无右孩子或者右孩子已经被遍历过了,则直接输出top的data
if (top->_right == NULL || last == top->_right)
{
printf("%d ", top->_data);
StackPop(&s);
}
else
{
//进行到这里说明top有右孩子且尚未遍历过
cur = top->_right;
last = top->_right;
}
}
}
##queue.h
typedef BTNode* QueueDataType;
typedef struct QueueNode
{
QueueDataType _data;
struct QueueNode* _next;
}QueueNode;
typedef struct Queue
{
QueueNode* _head;
QueueNode* _tail;
}Queue;
void QueueInit(Queue* q)
{
assert(q);
q->_head = NULL;
q->_tail = NULL;
}
QueueNode* BuyQueueNode(QueueDataType x)
{
QueueNode* node = (QueueNode*)malloc(sizeof(QueueNode));
node->_data = x;
node->_next = NULL;
return node;
}
void QueuePush(Queue* q, QueueDataType x)
{
assert(q);
if (q->_tail == NULL)
{
q->_head = q->_tail = BuyQueueNode(x);
}
else
{
q->_tail->_next = BuyQueueNode(x);
q->_tail = q->_tail->_next;
}
}
void QueuePop(Queue* q)
{
if (q->_head == NULL)
{
return;
}
else
{
QueueNode* next = q->_head->_next;
free(q->_head);
q->_head = next;
if (q->_head == NULL)
{
q->_tail = NULL;
}
}
}
QueueDataType QueueFront(Queue* q)
{
assert(q->_head);
return q->_head->_data;
}
QueueDataType QueueBack(Queue* q)
{
return q->_tail->_data;
}
size_t QueueSize(Queue* q)
{
QueueNode* cur = q->_head;
size_t size = 0;
while (cur)
{
++size;
cur = cur->_next;
}
return size;
}
// 空 返回0
// 非空 返回1
int QueueEmpty(Queue* q)
{
if (q->_head == NULL)
return 0;
else
return 1;
}
##stack.h
#pragma once
#include<stdio.h>
#include<windows.h>
#include<assert.h>
typedef BTNode* STDataType;
#define Stack_size 10
typedef struct Stack
{
STDataType* _array;//数组指针
size_t _top; //栈顶
size_t _end;//最大容量
}Stack;
// 栈的实现接口
void StackInit(Stack* s)//栈的初始化
{
assert(s);
s->_array = (STDataType*)malloc(sizeof(STDataType)*Stack_size);
s->_end = Stack_size;
s->_top = 0;
}
void StackPush(Stack* s, STDataType x)//入栈
{
assert(s);
if (s->_end == s->_top)//栈已满
{
s->_end *= 2;
s->_array = (STDataType*)realloc(s->_array, sizeof(STDataType)*(s->_end));
s->_array[s->_top] = x;
(s->_top)++;
}
else
{
s->_array[s->_top] = x;
(s->_top)++;
}
}
void Stack_print(Stack *s)
{
if (s == NULL)
{
return;
}
while ((s->_top)--)
{
printf("%d\t", s->_array[s->_top]);
}
}
void StackPop(Stack* s)//出栈
{
assert(s);
if (s->_top == 0)
{
printf("the stack is empty");
}
else
{
s->_top--;
}
}
STDataType StackTop(Stack* s)//取栈顶元素
{
assert(s);
assert(s->_top);
int num = s->_top;
return s->_array[(--num)];
}
size_t StackSize(Stack* s)//栈的长度
{
assert(s);
return s->_end;
}
int StackEmpty(Stack* s)//判断栈是否为空
{
if (s->_top == 0)
{
return 0;
}
else
{
return 1;
}
}
##test.c
#include"binarytree.h"
void test()
{
int a[] = { 1, 2, 3, '#', '#',4,'#', '#', 5, 6,'#' ,'#' ,'#' };
int index = 0;
BTNode *root = BinaryTreeCreateByPrev(a, &index, '#');
BTreePrevOrder(root);
printf("\n");
BTreeInOrder(root);
printf("\n");
BTreePostOrder(root);
printf("\n");
printf("该树有%d个节点\n", BTreeSize(root));
printf("该树有%d个叶子节点\n", BTreeLeafSize(root));
printf("该树第3层的节点数为%d\n", BTreeKLevelSize(root, 3));
printf("该树的深度为%d\n", BTreeDepth(root));
printf("%d\n", BTreeFind(root, 3)->_data);
printf("%d\n", IsCompleteBTree(root));
/*BTreePrevOrderNonR(root);
printf("\n");
BTreeInOrderNonR(root);
printf("\n");
BTreePostOrderNonR(root);*/
}
int main()
{
test();
system("pause");
return 0;
}