二叉树(三)

一、二叉树的遍历

二叉树遍历是按照某种特定的规则,依次对二叉树中的结点进行相应的操作,并且每个结点只操作一次。

1.前序遍历(先根遍历)

前序遍历(Preorder Traversal也叫先序遍历)------根、左子树、右子树。属于DFS(深度优先遍历)。空用N表示。

// 前序遍历空用N表示
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	printf("%d ", root->_data);
	PrevOrder(root->_left);
	PrevOrder(root->_right);
}

// 前序遍历不打印空
void PrevOrder(BTNode* root)
{
	if (root)
	{
		printf("%d ", root->_data);
		PrevOrder(root->_left);
		PrevOrder(root->_right);
	}
}

2.中序遍历(中根遍历)

中序遍历(Inorder Traversal)------左子树、根、右子树。空用N表示。

// 中序遍历空用N表示
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	InOrder(root->_left);
	printf("%d ", root->_data);
	InOrder(root->_right);
}

3.后序遍历(后根遍历)

后序遍历(Postorder Traversal)------左子树、右子树、根。空用N表示。

// 后序遍历空用N表示
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	PostOrder(root->_left);
	PostOrder(root->_right); 
	printf("%d ", root->_data);
}

4.层序遍历

设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第2层上的结点,接着是第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。**层序遍历是非递归遍历。**属于BFS(广度优先遍历)。

需要用到队列的代码,可以将之前写的代码拷贝过来(源代码->添加->现有项)。

// 层序遍历
#include"Queue.h"
void TreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);

		printf("%d ", front->_data);

		if (front->_left)
			QueuePush(&q, front->_left);

		if (front->_right)
			QueuePush(&q, front->_right);
	}
	QueueDestroy(&q);
}

其中Queue.h文件中要修改:

typedef struct BinaryTreeNode* QDataType;//要使用原生类型

二、二叉树结点个数

// 二叉树结点个数(错误示范)
int TreeSize(BTNode* root)
{
	static int size = 0;//静态
	if (root == NULL)
		return 0;
	else
		++size;
	TreeSize(root->_left);
	TreeSize(root->_right);
	return size;//打印结果会累加
}

正确写法:递归遍历思路

// 二叉树结点个数,方法一
int size = 0;
int TreeSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	else
		++size;
	TreeSize(root->_left);
	TreeSize(root->_right);
	return size;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	size = 0;
	printf("二叉树结点个数:%d\n", TreeSize(root));
	size = 0;
	printf("二叉树结点个数:%d\n", TreeSize(root));
	return 0;
}


// 二叉树结点个数,方法二
int TreeSize(BTNode* root, int* psize)
{
	if (root == NULL)
		return 0;
	else
		++(*psize);
	TreeSize(root->_left, psize);
	TreeSize(root->_right, psize);
	return *psize;//可以不要返回值
}
int main()
{
	BTNode* root = CreatBinaryTree();
	int size = 0;
	printf("二叉树结点个数:%d\n", TreeSize(root, &size));
	size = 0;
	printf("二叉树结点个数:%d\n", TreeSize(root, &size));
	return 0;
}

分治(分而治之)递归思路:

// 二叉树结点个数,方法三
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->_left) + TreeSize(root->_right) + 1;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	printf("TreeSize:%d\n", TreeSize(root));
	return 0;
}

三、二叉树叶子结点个数

int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->_left == NULL && root->_right == NULL)//只有一个叶子
		return 1;
	return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}

四、二叉树高度

为空是0,不为空就是左子树高度和右子树高度中大的加1。

//方法一:
int fmax(int x, int y)
{
	return x > y ? x : y;
}
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	return fmax(TreeHeight(root->left), TreeHeight(root->right)) + 1;
}

//方法二:
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftHeight = TreeHeight(root->_left);
	int rightHeight = TreeHeight(root->_right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

LCR 175. 计算二叉树的深度 - 力扣(LeetCode)下面代码OJ过不了,效率问题

//OJ不能通过
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

五、二叉树第k层节点个数

int TreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	// 子问题
	return TreeLevelKSize(root->_left, k - 1) + TreeLevelKSize(root->_right, k - 1);
}

六、二叉树查找值为x的节点

若有多个值为x的节点,返回第一次找到的节点,因为找到值为x的节点就不会再往下找了(若左子树找到值为x的节点,就不会再找右子树的节点)。

BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
	BTNode* ret1 = TreeFind(root->_left, x);
	if (ret1)
		return ret1;
	BTNode* ret2 = TreeFind(root->_right, x);
	if (ret2)
		return ret2;
	return NULL;
}

七、二叉树的销毁

如果是空树,不需要销毁。

使用后序遍历,先销毁左子树,在销毁右子树,最后释放根结点。

void TreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestory(root->_left);
	TreeDestory(root->_right);
	free(root);
}

八、判断二叉树是否是完全二叉树

①层序遍历走,空也进队列;

②遇到第一个空节点时,开始判断,后面全空就是完全二叉树,后面有非空就不是完全二叉树。

bool TreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		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 false;
		}
	}
	QueueDestroy(&q);
	return true;
}

九、二叉树链式结构的实现

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;
BTNode* BuyNode(int x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	node->_data = x;
	node->_left = NULL;
	node->_right = NULL;
	return node;
}
BTNode* CreatBinaryTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);
	BTNode* node5 = BuyNode(5);
	BTNode* node6 = BuyNode(6);
	node1->_left = node2;
	node1->_right = node4;
	node2->_left = node3;
	node4->_left = node5;
	node4->_right = node6;
	return node1;
}
// 前序遍历空用N表示
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	printf("%d ", root->_data);
	PrevOrder(root->_left);
	PrevOrder(root->_right);
}
// 中序遍历空用N表示
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	InOrder(root->_left);
	printf("%d ", root->_data);
	InOrder(root->_right);
}
// 后序遍历空用N表示
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");
		return;
	}
	PostOrder(root->_left);
	PostOrder(root->_right); 
	printf("%d ", root->_data);
}
// 二叉树结点个数
int TreeSize(BTNode* root)
{
	return root == NULL ? 0 : TreeSize(root->_left) + TreeSize(root->_right) + 1;
}
// 二叉树叶子结点个数
int TreeLeafSize(BTNode* root)
{
	if (root == NULL)
		return 0;
	if (root->_left == NULL && root->_right == NULL)//只有一个叶子
		return 1;
	return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}
// 二叉树的高度:为空是0,不为空就是左子树高度和右子树高度大的加1
int TreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;
	int leftHeight = TreeHeight(root->_left);
	int rightHeight = TreeHeight(root->_right);
	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}
// 二叉树第k层节点个数
int TreeLevelKSize(BTNode* root, int k)
{
	if (root == NULL)
		return 0;
	if (k == 1)
		return 1;
	return TreeLevelKSize(root->_left, k - 1) + TreeLevelKSize(root->_right, k - 1);
}
// 二叉树查找值为x的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
	BTNode* ret1 = TreeFind(root->_left, x);
	if (ret1)
		return ret1;
	//return TreeFind(root->_right, x);
	BTNode* ret2 = TreeFind(root->_right, x);
	if (ret2)
		return ret2;
	return NULL;
}
// 二叉树销毁
void TreeDestory(BTNode* root)
{
	if (root == NULL)
		return;
	TreeDestory(root->_left);
	TreeDestory(root->_right);
	free(root);
}
// 层序遍历
#include"Queue.h"
void TreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%d ", front->_data);
		if (front->_left)
			QueuePush(&q, front->_left);
		if (front->_right)
			QueuePush(&q, front->_right);
	}
	QueueDestroy(&q);
}
// 判断二叉树是否是完全二叉树
bool TreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	if (root)
		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 false;
		}
	}
	QueueDestroy(&q);
	return true;
}
int main()
{
	BTNode* root = CreatBinaryTree();
	PrevOrder(root);
	printf("\n"); 
	InOrder(root);
	printf("\n");
	PostOrder(root);
	printf("\n");
	printf("TreeSize:%d\n", TreeSize(root));
	printf("TreeLeafSize:%d\n", TreeLeafSize(root));
	printf("TreeHeight:%d\n", TreeHeight(root));
	printf("TreeLevelKSize:%d\n", TreeLevelKSize(root, 3));
	TreeLevelOrder(root);
	printf("\n");
	TreeComplete(root);
	TreeDestory(root);
	root = NULL;
	return 0;
}
相关推荐
shymoy14 分钟前
Radix Sorts
数据结构·算法·排序算法
木向2 小时前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越2 小时前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法
小爬虫程序猿4 小时前
如何利用Python解析API返回的数据结构?
数据结构·数据库·python
pianmian18 小时前
python数据结构基础(7)
数据结构·算法
ChoSeitaku11 小时前
链表交集相关算法题|AB链表公共元素生成链表C|AB链表交集存放于A|连续子序列|相交链表求交点位置(C)
数据结构·考研·链表
偷心编程11 小时前
双向链表专题
数据结构
香菜大丸11 小时前
链表的归并排序
数据结构·算法·链表
jrrz082811 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
@小博的博客12 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习