目录
二叉树的层序遍历
不同于上一节所说的前中后序遍历
层序遍历是从顶层的根节点开始,再自左向右访问第二层的结点,访问完成之后,再自左向右访问第三层结点,直到最后一个结点停止.
也就是说从上到下,从左到右打印二叉树的每一个节点.
层序遍历的结果是ABCD,这样应该就能明白了 .
下面来看代码的实现:
思路:
层序遍历每次都是自左向右,自上而下访问,我们可以用队列来模拟这个过程,既将访问到的每个元素保存到队列中,然后每次输出队头元素即是我们访问的元素.
实现:
1.先将二叉树的根节点存放到队列中,若队列不为空,则输出队头元素
2.判断该结点是否有孩子结点,(先判断是否有左孩子结点,再判断右孩子)。若有,则将这个结点放到队列中.
3.每次将访问过的(既已经打印的元素)删掉.
4.循环以上操作,直到Tree为空.
代码如下:
void BinaryTreeLevelOrder(BTNode* root)
{
Queue q;//这个队列是模拟实现的,不是c++的stl,如果用的话,就替换掉对应的函数就可以.
QueueInit(&q);//队列初始化
if (root)
{
QueuePush(&q, root);//将根节点入到队列当中
}
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
printf("%d ", front->data);
QueuePop(&q);
if (front->left)//如果左孩子不为空,就入队列
{
QueuePush(&q, front->left);
}
if (front->right)//若右孩子不为空,也入到队列
{
QueuePush(&q, front->right);
}
}
QueueDestroy(&q);
}
关于二叉树的五个问题
说到二叉树的操作,绝大部分都是递归操作.
这种递归操作让人难以理解,尤其是在只看代码的情况下.
所以我对每个题进行画图示意,这样能帮助我们更好的理解.
文字讲解将非常困难,而且不易理解.
1.求二叉树的结点个数
代码如下:
int BinaryTreeSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
看下图图解:
相当于是是每次递归把它的子树的结点返回来了,例如D的没有左右子树,所以返回0+0,但是他自身还算一个,所以+1.
B没有左子树,所以返回0,有右子树,是D,D经过递归遍历,只有一个结点,所以给B返回1
然后再加上B本身这个结点一共2个返回给A,所以A的子树有2个结点.
右子树也是同样的道理.
递归无非就是把大事化小,把一个问题划分成若干相同的小问题进行解决.
2.求二叉树叶子结点个数
这个和上面那个题就有一些区别了,上面那个题子树每次返回的时候都要加上本身那个结点的个数,既+1.
但是这个题是求叶子结点,即只有没有左右孩子结点的结点才+1,否则+0(相当于不做处理).
代码如下:
int BinaryTreeLeafSize(BTNode* root)
{
if (root == NULL)
{
return NULL;
}
//如果该结点没有左右孩子结点,说明是叶子结点,返回1.
if (root->left == NULL && root->right == NULL)
{
return 1;
}
//遍历左右子树
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
还是像之前一样,靠画图来逐渐理解.
3.求二叉树第k层结点个数
总体思路是:求第k层结点的个数,转化为求以根节点的左孩子为根的k-1层节点数
加上根节点的右孩子为根的k-1层节点数.
说的很抽象,比如求第3层的结点,可以转化成求根节点的左右子树的第2层节点数,再继续
成为第二层每个节点的左右子树的第1层结点,这样在k==1的的时候,如果结点存在,就直接返回1.
代码如下:
int BinaryTreeLevelKSize(BTNode* root, int k)
{
assert(k >= 1);
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
图解如下:
4.在二叉树中寻找特定的值
可采用前序遍历的方式查找指定的值.若有则返回值,没有则返回NULL.
代码如下:
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
{
return NULL;
}
if (root-> data== x)//如果当前结点的值等于指定数据,则直接返回.
{
return root;
}
BTNode* ret1 = BinaryTreeFind(root->left, x);//保存左子树遍历的结果
if (ret1)//如果不为空,说明已经找到了,则直接返回结果
{
return ret1;
}
BTNode* ret2 = BinaryTreeFind(root->right, x);//若左子树没有,则会遍历右子树,会保存右子树遍历结果
if (ret2)//若不为空说明找到,直接返回
{
return ret2;
}
return NULL;//若左右子树都没有找到,返回结果为空
}
画图来理解一下:
这样就完成二叉树的查找操作了.
总代码如下:
Tree.h文件
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<assert.h>
#include<stdbool.h>
typedef char BTDataType;
typedef struct BinaryTreeNode
{
struct BinartTreeNode* left;
struct BinartTreeNode* right;
BTDataType data;
}BTNode;
//创建节点
BTNode* BuyNode(BTDataType x);
// 二叉树节点个数
int BinaryTreeSize(BTNode* root);
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
Tree.c文件:
#include"Tree.h"
#include"Queue.h"
BTNode* BuyNode(BTDataType x)
{
BTNode* node = (BTNode*)malloc(sizeof(BTNode));
assert(node);
node->data = x;
node->left = NULL;
node->right = NULL;
return node;
}
// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
if (root == NULL)
{
return 0;
}
return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
if (root == NULL)
{
return NULL;
}
if (root->left == NULL && root->right == NULL)
{
return 1;
}
return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
assert(k >= 1);
if (root == NULL)
{
return 0;
}
if (k == 1)
{
return 1;
}
return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
//查找二叉树指定值
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
if (root == NULL)
{
return NULL;
}
if (root-> data== x)
{
return root;
}
BTNode* ret1 = BinaryTreeFind(root->left, x);
if (ret1)
{
return ret1;
}
BTNode* ret2 = BinaryTreeFind(root->right, x);
if (ret2)
{
return ret2;
}
return NULL;
}
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
Queue q;
QueueInit(&q);
if (root)
{
QueuePush(&q, root);
}
while (!QueueEmpty(&q))
{
BTNode* front = QueueFront(&q);
printf("%d ", front->data);
QueuePop(&q);
if (front->left)
{
QueuePush(&q, front->left);
}
if (front->right)
{
QueuePush(&q, front->right);
}
}
QueueDestroy(&q);
}
队列代码:用来模拟队列进行层序遍历.
如果用c++的stl里的queue可以直接省略这一文件
Queue.h文件
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
struct BinaryTreeNode;
typedef struct BinaryTreeNode* QDataType;
typedef struct QueueNode
{
struct QueneNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* head;
QNode* tail;
}Queue;
void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
void QueuePush(Queue* pq, QDataType x);
void QueuePop(Queue* pq);
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);
bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
Queue.c文件
//初始化
void QueueInit(Queue* pq)
{
assert(pq);
pq->head = pq->tail = NULL;
}
//销毁
void QueueDestroy(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
pq->head = pq->tail = NULL;
}
//插入
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
printf("Malloc fail\n");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
if (pq->tail == NULL)
{
pq->head = pq->tail = newnode;
}
else
{
pq->tail->next = newnode;
pq->tail = newnode;
}
}
//删除
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
//只有一个结点
if (pq->head->next == NULL)
{
free(pq->head);
pq->head = pq->tail = NULL;
}
//多个结点
else
{
QNode* next = pq->head->next;
free(pq->head);
pq->head = next;
}
}
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->head->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->tail->data;
}
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->head == NULL;
}
int QueueSize(Queue* pq)
{
assert(pq);
QNode* cur = pq->head;
int size = 0;
while (cur != NULL)
{
cur = cur->next;
size++;
}
return size;
}
测试代码:
Test.c文件:
#include"Tree.h"
#include"Queue.h"
BTNode* CreatBinaryTree()
{
BTNode* node1 = BuyNode(1);
assert(node1);
BTNode* node2 = BuyNode(2);
assert(node2);
BTNode* node3 = BuyNode(3);
assert(node3);
BTNode* node4 = BuyNode(4);
assert(node4);
BTNode* node5 = BuyNode(5);
assert(node5);
BTNode* node6 = BuyNode(6);
assert(node6);
BTNode* node7 = BuyNode(7);
assert(node7);
node1->left = node2;
node1->right = node3;
node2->left = node4;
node2->right = node5;
node3->left = node6;
node3->right = node7;
return node1;
}
int main()
{
BTNode* tree = CreatBinaryTree();
//测试层序遍历,当然你可以在这修改测试任意模块的功能.
BinaryTreeLevelOrder(tree);
return 0;
}
这次文章就结束啦,后面还会有更多的二叉树题目来巩固哦.
如果大家有看不懂或错误的地方.欢迎提问或指正哦~