Bootstrap

二叉树的四种遍历方式以及必备的面试题(附图解)

二叉树的四种遍历方式以及必备的面试题



前言

本文介绍二叉树前序遍历、中序遍历、后序遍历、层序遍历以及各自相关的面试OJ题的讲解!


一、构建一个二叉树

构建如图所示的二叉树,在这里不做过多介绍,想了解怎么构建的可以参考之前的博客!

在这里插入图片描述


代码如下(示例):

typedef char BTDataType;
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
	BTDataType data;
}BTNode;
BTNode* BuyNode(BTDataType x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		printf("malloc fail\n");
		exit(-1);
	}
	node->data = x;
	node->left = node->right = NULL;
	return node;
}
BTNode* CreatBinaryTree()
{
	BTNode* nodeA = BuyNode('A');
	BTNode* nodeB = BuyNode('B');
	BTNode* nodeC = BuyNode('C');
	BTNode* nodeD = BuyNode('D');
	BTNode* nodeE = BuyNode('E');
	BTNode* nodeF = BuyNode('F');
	nodeA->left = nodeB;
	nodeA->right = nodeC;
	nodeB->left = nodeD;
	nodeC->left = nodeE;
	nodeC->right = nodeF;
	return nodeA;
}

二、四种遍历方式

1.前序遍历

前序遍历的顺序为 根 —> 左子树 —> 右子树,下面给大家介绍一种简便方法


在这里插入图片描述


代码如下(示例):

// 二叉树前序遍历 
void PreOrder(BTNode* root)
{
	if (root == NULL) {
		printf("NULL ");
		return;
	}
	printf("%c ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

2.中序遍历

中序遍历的顺序为 左子树 —> 根 —> 右子树
在这里插入图片描述


代码如下(示例):

// 二叉树中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL) {
		printf("NULL ");
		return;
	}
	InOrder(root->left);
	printf("%C ", root->data);
	InOrder(root->right);
}

3.后序遍历

后序遍历的顺序为 左子树 —> 右子树 —> 根
在这里插入图片描述


代码如下(示例):

// 二叉树后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	PostOrder(root->left);
	PostOrder(root->right);
	printf("%C ", root->data);
}

附加: 前三种遍历对比图

在这里插入图片描述


4.层序遍历

层序遍历就是一层一层地遍历,如下图+源码!
在这里插入图片描述


这里我们用队列来实现层序遍历,如下图思路!由于这里会遇到大量队列知识,可以参考:队列实现


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


代码如下(示例):

// 层序遍历
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->data);

		// 孩子带进队列
		if (front->left)
			QueuePush(&q, front->left);

		if (front->right)
			QueuePush(&q, front->right);
	}
	printf("\n");
	QueueDestroy(&q);
}

三、四种遍历相关的面试题

1.第一题:144. 二叉树的前序遍历

Leedcode链接


(1)题目

在这里插入图片描述

题目如下(示例):

int* preorderTraversal(struct TreeNode* root, int* returnSize)
{ }

(2)思路

这里要注意:这道题的返回值为 int* 即要返回一个数组,且*returnSize为数组元素大小
1.size需要自己计算,可以用之前写过的 TreeSize ,不太懂得可以参考 :二叉树节点个数
2.用1子函数来写前序遍历的三步
3.在递归的时候要注意传的是i的地址,因为在传参时,形参是实参的一份临时拷贝,要传&i
4.最后把size 给 *returnSize ,以保证数组大小!


(3)源码

代码如下(示例):

//先求下数组的大小,便于开辟空间
int Treesize(struct TreeNode* root)
{
    return root == NULL ? 0 : Treesize(root->left) + Treesize(root->right) + 1 ;
}
void _preorderTraversal(struct TreeNode* root , int* a, int* pi)
{
     if(root == NULL)
    {
        return;
    }
    a[(*pi)++] = root->val;
    _preorderTraversal(root -> left ,a,pi);
    _preorderTraversal(root->right , a ,pi);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
    int size = Treesize(root);
    int* a = (int*)malloc(sizeof(int)*size);
    int i = 0;
    _preorderTraversal(root , a , &i);
    *returnSize = size;
    return a;
}

2.第二题:94. 二叉树的中序遍历

Leedcode链接

3.第三题:145. 二叉树的后序遍历

Leecode链接


第二题和第三题和第一题解法一样,这里不做过多介绍,这里直接给出答案!

第二题答案:如下(示例):

int Treesize(struct TreeNode* root)
{
    return root == NULL ? 0 : Treesize(root->left) + Treesize(root->right) + 1 ;
}
void _inorderTraversal(struct TreeNode* root , int* a, int* pi)
{
     if(root == NULL)
    {
        return;
    }
    _inorderTraversal(root -> left ,a,pi);
    a[(*pi)++] = root->val;
    _inorderTraversal(root->right , a ,pi);
}
int* inorderTraversal(struct TreeNode* root, int* returnSize)
{
    int size = Treesize(root);
    int* a = (int*)malloc(sizeof(int)*size);
    int i = 0;
    _inorderTraversal(root , a , &i);
    *returnSize = size;
    return a;
}

第三题答案:如下(示例):

int Treesize(struct TreeNode* root)
{
    return root == NULL ? 0 : Treesize(root->left) + Treesize(root->right) + 1 ;
}
void _postorderTraversal(struct TreeNode* root , int* a, int* pi)
{
     if(root == NULL)
    {
        return;
    }
    _postorderTraversal(root -> left ,a,pi);
    _postorderTraversal(root->right , a ,pi);
    a[(*pi)++] = root->val;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize)
{
    int size = Treesize(root);
    int* a = (int*)malloc(sizeof(int)*size);
    int i = 0;
    _postorderTraversal(root , a , &i);
    *returnSize = size;
    return a;
}

4.第四题:判断二叉树是否是完全二叉树

(1)思路

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


(2)源码

代码如下(示例):

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		if (front == NULL)
		{
			break;
		}
		else
		{
			QueuePush(&q, front->left);
			QueuePush(&q, front->right);
		}
	}

	// 遇到空了以后,检查队列中剩下的节点
	// 1、剩下全是空给,则是完全二叉树
	// 2、剩下存在非空,则不是完全二叉树
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		if (front)
		{
			QueueDestroy(&q);
			return false;
		}
	}

	QueueDestroy(&q);
	return true;
}

5.第五题:KY11 二叉树遍历

牛客网链接

(1)题目

在这里插入图片描述


(2)思路

这道题需要分成不同地模块来完成!
1.构建树,用 结构体 TreeNode
2.写中序遍历,不会写的看前面文章!
3.如果是 # 就跳过并返回NULL ,如下图所示


在这里插入图片描述在这里插入图片描述


构建完二叉树之后,就可以对每一个节点进行中序遍历并打印,不会中序遍历的可以参考前面!
在这里插入图片描述


(3)源码

代码如下(示例):

#include<stdio.h>
#include <stdlib.h>
struct TreeNode {
    struct TreeNode* left;
    struct TreeNode* right;
    char val;
};
struct TreeNode* CreateTree(char* str, int* pi) {
    if (str[*pi] == '#') {
        (*pi)++;
        return NULL;
    }
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    root -> val = str[(*pi)++];
    root -> left = CreateTree(str, pi);
    root -> right = CreateTree(str, pi);
    return root;
}
void InOrder(struct TreeNode* root) {
    if (root == NULL)
        return;
    InOrder(root->left);
    printf("%c ", root->val);
    InOrder(root->right);
}
int main() {
    char str[100];
    while ((scanf("%s", str) != EOF)) {
        int i = 0;
        struct TreeNode* root = CreateTree(str, &i);
        InOrder(root);
    }
    return 0;
}

最后:销毁二叉树

在我们每次创建完二叉树之后要销毁二叉树,否则会导致内存泄漏

(1)源码

代码如下(示例):

void BinaryTreeDestory(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}

	BinaryTreeDestory(root->left);
	BinaryTreeDestory(root->right);
	free(root);
}

(2)递归图解

想销毁如图所示的二叉树!为了方便我只画了一条路径上的销毁递归图,感兴趣的可以都画!
在这里插入图片描述


在这里插入图片描述


总结

以上就是今天要讲的内容,本文介绍二叉树的四种遍历方式以及必备的面试题。
如果我的博客对你有所帮助记得三连支持一下,感谢大家的支持!
在这里插入图片描述

;