1. 数据结构定义
二叉树节点结构(BTNode):
val:存储节点的值。
_left:指向左子节点的指针。
_right:指向右子节点的指针。
2. 创建节点
createNode:
输入一个字符,动态分配内存给新的节点,初始化该节点的值和左右子节点指针。
3. 树的遍历
前序遍历 (PrevOrder):
遍历顺序为:根 → 左子树 → 右子树,打印每个节点的值。
中序遍历 (middleOrder):
遍历顺序为:左子树 → 根 → 右子树,打印每个节点的值。
后序遍历 (lateOrder):
遍历顺序为:左子树 → 右子树 → 根,打印每个节点的值。
4. 树的属性计算
TreeSize:
计算并返回树的节点总数。
TreeLeafSize:
计算并返回树的叶子节点数量(没有子节点的节点)。
TreeDepth:
计算并返回树的深度(从根节点到叶子节点的最长路径)。
5. 其他树操作
第 k 层节点个数 (BinaryTreeLevelKSize):
计算并返回树中第 k 层的节点数量。
查找节点 (BinaryTreeFind):
通过节点值查找树中对应的节点,如果找到了就返回该节点的指针。
销毁树 (DestoryTree):
递归释放树中所有节点分配的内存,以避免内存泄漏。
6. 层序遍历
层序遍历 (BinaryTreeLevelOrder):
采用队列实现的层序遍历(广度优先),按层打印每个节点的值。
7. 判断完全二叉树
判断是否完全二叉树 (BinaryTreeComplete):
使用队列检查二叉树是否为完全二叉树。访问完所有可以访问的节点后,若发现有非空节点,则返回0(不是完全二叉树);否则,返回1(是完全二叉树)。
8. main 函数
创建了一棵示例二叉树,包含7个节点(A、B、C、D、E、F)。
调用各种功能函数,测试树的遍历、属性计算、查找、层序遍历和判断是否完全二叉树,并打印结果。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include"Queue.h"
typedef char BTDateType;
/* A
B C
D E*/
typedef struct BinaryTreeNode
{
BTDateType val;
struct BinaryTreeNode* _left;
struct BinaryTreeNode* _right;
}BTNode;
BTNode* creatNode(BTDateType x)
{
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
node->val = x;
node->_left = NULL;
node->_right = NULL;
return node;
}
//前序
void PrevOrder(BTNode* node)
{
if (!node)
{
printf("NULL ");
return;
}
printf("%c ", node->val);
PrevOrder(node->_left);
PrevOrder(node->_right);
}
//中序
void middleOrder(BTNode* node)
{
if (!node)
{
printf("NULL ");
return;
}
middleOrder(node->_left);
printf("%c ", node->val);
middleOrder(node->_right);
}
//后序
void lateOrder(BTNode* node)
{
if (!node)
{
printf("NULL ");
return;
}
lateOrder(node->_left);
lateOrder(node->_right);
printf("%c ", node->val);
}
int TreeSize(BTNode* node)
{
if (node == NULL)
{
return 0;
}
return 1 + TreeSize(node->_left) + TreeSize(node->_right);
}
//叶子数
int TreeLeafSize(BTNode* node)
{
if (node == NULL)
return 0;
if (node->_left == NULL && node->_right == NULL)
return 1;
else
return TreeLeafSize(node->_left) + TreeLeafSize(node->_right);
}
//树深度
int TreeDepth(BTNode* node)
{
if (node == NULL)
{
return 0;
}
int leftDepth = TreeDepth(node->_left);
int rightDepth = TreeDepth(node->_right);
//取左右子树深度最深一颗并加1
return (leftDepth > rightDepth) ? leftDepth + 1: rightDepth + 1;
}
//二叉树第k层节点个数
//当前树的第k层,可以换成左右子树的第k-1层
//层数==1就不需要再分解了
int BinaryTreeLevelKSize(BTNode* root,int k)
{
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return BinaryTreeLevelKSize(root->_left, k - 1)
+ BinaryTreeLevelKSize(root->_right, k - 1);
}
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDateType x)
{
if (root == NULL) {
return NULL; // 如果根节点为空,返回NULL
}
if (root->val == x) {
return root; // 如果当前节点的值与查找值相等,返回该节点
}
// 递归查找左子树
BTNode* node = BinaryTreeFind(root->_left, x);
if (node != NULL) {
return node; // 如果在左子树找到目标节点,返回该节点
}
// 递归查找右子树
node = BinaryTreeFind(root->_right, x);
return node; // 返回结果,无论是找到的节点还是NULL
}
//销毁
void DestoryTree(BTNode* root)
{
if (root == NULL)
{
return;
}
DestoryTree(root->_left);
DestoryTree(root->_right);
free(root);
}
//二叉树层序遍历
//利用队列,先进先出,
//根先进队列,
//迭代->队列不为空,出队头数据,顺便把左右孩子带进队列,
//直到队列为空,截止
void BinaryTreeLevelOrder(BTNode* root)
{
if (root == NULL)
return;
Queue q;
QueueInit(&q);
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
printf("%c ", front->val);
if (front->_left)
{
QueuePush(&q, front->_left);
}
if (front->_right)
{
QueuePush(&q, front->_right);
}
}
QueueDestroy(&q);
printf("\n");
}
//判断二叉树是不是完全二叉树
//完全二叉树: A B C D E NULL NULL NULL NULL 返回 1
//非完全二叉树: A B C D E NULL NULL F NULL NULL 返回 0
int BinaryTreeComplete(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root == NULL)
return 1;
QueuePush(&q, root);
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
//遇到空,跳出判断
if (front == NULL)
{
break;
}
QueuePush(&q, front->_left);
QueuePush(&q, front->_right);
}
//检查队列后面还有没有非空的值
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
QueuePop(&q);
//非空,即不是完全二叉树
if (front)
{
//销毁队列!
QueueDestroy(&q);
return 0;
}
}
QueueDestroy(&q);
return 1;
}
int main()
{
BTNode* A = creatNode('A');
BTNode* B = creatNode('B');
BTNode* C = creatNode('C');
BTNode* D = creatNode('D');
BTNode* E = creatNode('E');
BTNode* F = creatNode('F');
A->_left = B;
A->_right = C;
B->_left = D;
B->_right = E;
C->_right = F;
printf("前序: ");
PrevOrder(A);
printf("\n");
printf("中序: ");
middleOrder(A);
printf("\n");
printf("后序: ");
lateOrder(A);
printf("\n");
//getchar();
int size = TreeSize(A);
printf("%d \n", size);
size = TreeSize(B);
printf("%d \n", size);
size = TreeLeafSize(A);
printf("A叶节点个数: %d\n", size);
size = TreeLeafSize(B);
printf("B叶节点个数: %d\n", size);
size = TreeLeafSize(C);
printf("C叶节点个数: %d\n", size);
size = TreeLeafSize(A);
printf("A结点二叉树深度为:%d\n", size);
size = TreeLeafSize(B);
printf("B结点二叉树深度为:%d\n", size);
size = TreeLeafSize(D);
printf("D结点二叉树深度为:%d\n", size);
size = BinaryTreeLevelKSize(A, 3);
printf("节点个数:%d \n", size);
BTNode* node = BinaryTreeFind(A, A);
if (node != NULL)
{
printf("1%c \n", node->val);
}
BinaryTreeLevelOrder(A);
int ret = BinaryTreeComplete(A);
if (ret)
{
printf("是完全二叉树\n");
}
else
printf("不是完全二叉树\n");
DestoryTree(A);
return 0;
}
附:队列实现代码
//头文件Queue.h
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
//声明一下,外部类型
extern struct BinaryTreeNode;
typedef struct BinaryTreeNode* QDateType;
typedef struct QueueNode
{
QDateType val;
struct QueueNode* next;
}QueueNode;
typedef struct Queue
{
QueueNode* head;
QueueNode* tail;
}Queue;
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePop(Queue* pq);
void QueuePush(Queue* pq, QDateType x);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
QDateType QueueFront(Queue* pq);
QDateType QueueBack(Queue* pq);
====================================================================================
//源文件Queue.c
#define _CRT_SECURE_NO_WARNINGS
#include"Queue.h"
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
QueueNode* cur = pq->head;
while (cur)
{
QueueNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
QueueNode* QueueBuyNewNode(QDateType x)
{
QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
if (newNode == NULL)
{
printf("malloc fail\n");
exit(-1);
}
newNode->val = x;
newNode->next = NULL;
return newNode;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
QueueNode* newHead = pq->head->next;
free(pq->head);
pq->head = newHead;
if (pq->head == NULL)
{
//链表已删完,tail要置空,防止出现野指针
pq->tail = NULL;
}
}
void QueuePush(Queue* pq, QDateType x)
{
assert(pq);
QueueNode* newNode = QueueBuyNewNode(x);
if (pq->head == NULL)
{
pq->head = pq->tail = newNode;
}
else
{
pq->tail->next = newNode;
pq->tail = newNode;
}
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
int QueueSize(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
int size = 0;
QueueNode* cur = pq->head;
while (cur)
{
QueueNode* next = cur->next;
size++;
cur = next;
}
return size;
}
QDateType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->val;
}
QDateType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->val;
}