二叉树链式结构

本文介绍了二叉树链式结构的遍历,包括前序、中序、后序递归遍历以及层序遍历的概念和操作顺序,并强调了遍历在二叉树运算中的重要性。
摘要由CSDN通过智能技术生成

一、二叉树链式结构的遍历

1、概念:
所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问 题。 遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
遍历:按照某种规则,对二叉树中的每个节点进行相应的操作(打印、每个节点值+1),并且每个节点只能操作一次
在这里插入图片描述
2、前序/中序/后序的递归结构遍历:是根据访问结点操作发生位置命名

  1. NLR:前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。【根左右】
  2. LNR:中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。【左中右】
  3. LRN:后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。【左右中】

总结:三种遍历方式都是左子树在右子树之前进行遍历

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R(Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LRN分别又称为先根遍历、中根遍历和后根遍历

在这里插入图片描述
3、层序遍历:
除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。
在这里插入图片描述

二、实现链式数据结构的以下基本操作:

typedef struct Node
{
	int val;
	struct Node *left;
	struct Node *right;
} Node;

typedef struct ReturnType
{
	int use;// 创建树过程中用掉的值个数
	Node *root;// 创建好树的根节点
} ReturnType;

//二叉树的构建及遍历
ReturnType createTree(char preordered[], int size)
{
	char rootvalue = preordered[0];
	if (rootvalue == '#')
	{
		ReturnType returnvalue;
		returnvalue.root = NULL;
		returnvalue.use = 1;
		return returnvalue;
	}
	//前序遍历的第一个值就是根的值,
	//所以,取第一个值,创建当前树的根节点
	Node *root = (Node *)malloc(sizeof(Node));
	root->val = rootvalue;
	//用递归的思路创建当前树的
	//1)左子树
	//需要传入左子树的前序遍历值
	ReturnType left = createTree(preordered + 1, size - 1);
	//右子树
	//需要传入右子树的前序遍历值
	//右子树的前序遍历值,需要先计算创建左子树过程中用掉的值个树
	ReturnType right = createTree(preordered + 1 + left.use, size - 1 - left.use);
	root->left = left.root;
	root->right = right.root;
	//创建好后,返回
	//1)创建好树的根节点
	//2)创建树过程中用掉的节点个数
	ReturnType returnvalue;
	returnvalue.root = root;
	returnvalue.use = 1 + left.use + right.use;
	return returnvalue;
}


// 拷贝二叉树 
Node* CopyBinTree(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return NULL;
	}
	else
	{
		Node *copytree = (Node *)malloc(sizeof(Node));
		copytree->val = pRoot->val;
		copytree->left = pRoot->left;
		copytree->right = pRoot->right;
		return copytree;
	}
}

// 二叉树的三种遍历方式 
//前序遍历
void PreOrder(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return;
	}
	printf("%d", pRoot->val);
	PreOrder(pRoot->left);
	PreOrder(pRoot->right);
}
//非递归前序遍历
void PreOrderNor(Node* pRoot)
{
	Node * cur = pRoot;
	std::stack<Node *> st;
	while (cur != NULL || !st.empty())
	{
		while (cur != NULL)
		{
			printf("%d", cur->val);
			st.push(cur);
			cur = cur->left;
		}
		Node *top = st.top();
		st.pop();
		cur = top->right;
	}
}
//中序遍历
void InOrder(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return;
	}
	InOrder(pRoot->left);
	printf("%d", pRoot->val);
	InOrder(pRoot->right);
}
//非递归中序遍历
void InOrderNor(Node* pRoot)
{
	Node * cur = pRoot;
	std::stack<Node *> st;
	while (cur != NULL || !st.empty())
	{
		while (cur != NULL)
		{
			st.push(cur);
			cur = cur->left;
		}
		Node *top = st.top();
		printf("%d", top->val);
		st.pop();
		cur = top->right;
	}
}
//后序遍历
void PostOrder(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return;
	}
	PostOrder(pRoot->left);
	PostOrder(pRoot->right);
	printf("%d", pRoot->val);
}
//非递归后序遍历
void PostOrderNor(Node* pRoot)
{
	Node *cur = pRoot;
	Node *last = NULL;

	std::stack<Node *> st;
	while (cur != NULL || !st.empty())
	{
		while (cur != NULL)
		{
			st.push(cur);
			cur = cur->left;
		}
		Node *top = st.top();
		if (top->right == NULL || top->right == last)
		{
			st.pop();
			printf("%d", top->val);
			last = top;
		}
		else
		{
			cur = top->right;
		}
	}
}
//层序遍历
void LevelOrder(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return;
	}
	std::queue<Node *> q;
	q.push(pRoot);
	while (!q.empty())
	{
	//取队头元素
		Node *front = q.front();
		//该元素出队列
		q.pop();
		printf("%d", front->val);
		if (front->left != NULL)
		{
		//如果节点的左孩子存在--将左孩子存入队列
			q.push(front->left);
		}
		if (front->right != NULL)
		{
		//如果节点的右孩子存在--将右孩子存入队列
			q.push(front->right);
		}
	}
}

// 获取二叉树中节点的个数 
int GetNodeCount(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return 0;
	}
	int left = GetNodeCount(pRoot->left);
	int right = GetNodeCount(pRoot->right);
	return left + right + 1;
}

// 求二叉树的高度 
int Height(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return 0;
	}
	int left = Height(pRoot->left);
	int right = Height(pRoot->right);
	return (left > right ? left : right) + 1;
}

// 检测二叉树是否平衡O(N^2) 

//1.判断以根结点的树是否为二叉平衡树。求出左右子树的高度,判断它们的高度差是否超过了1。
//2.递归判断根的左子树是否为平衡二叉树
//3.递归判断根的右子树是否为平衡二叉树
//注意:空树也是平衡二叉树
int IsBalanceTree(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return 1;
	}
	int left = Height(pRoot->left);
	int right = Height(pRoot->right);
	int dif = left - right;
	if (dif> 1 || dif < -1)
	{
		return 0;
	}
	return IsBalanceTree(pRoot->left) && IsBalanceTree(pRoot->right);
}

// 获取二叉数中叶子节点的个数 
int GetLeafNodeCount(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return 0;
	}
	else if (pRoot->left == NULL && pRoot->right == NULL)
	{
		return 1;
	}
	else
	{
		return GetLeafNodeCount(pRoot->left) + GetLeafNodeCount(pRoot->right);
	}
}

// 获取二叉树第K层节点的个数 
int GetKLevelNodeCount(Node* pRoot, int K)
{
	assert(K >= 1);
	if (pRoot == NULL)
	{
		return 0;
	}
	else if (K== 1)
	{
		return 1;
	}
	else
	{
		return GetKLevelNodeCount(pRoot->left, K - 1) + GetKLevelNodeCount(pRoot->right, K - 1);
	}
}

// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{
	std::queue<BTNode*> q;
	int flag=0;
	//空树也是完全二叉树
	if (root == NULL)
		return 1;

	//非空
	//1、按照层序遍历规则找第一个不饱和的节点
	q.push(root);
	while (!q.empty())
	{
		BTNode* cur = q.front();
		if (flag)
		{
			//后续的节点不能有孩子
			if (cur->left || cur->right)
				return 0;
		}
		else
		{
			//找第一个不饱和的节点
			if (cur->left && cur->right)
			{
				q.push(cur->left);
				q.push(cur->right);
			}
			else if (cur->left)
			{
				//cur只有左孩子
				q.push(cur->left);
				flag = 1;
			}
			else if (cur->right)
			{
				//只有右孩子
				return 0;
			}
			else
			{
				flag = 1;
			}
			
		}
		q.pop();
	}
	return 1;
}
// 获取二叉树中某个节点的双亲节点 
Node* GetNodeParent(Node* pRoot, Node* pNode)
{
	if (pRoot == NULL)
	{
		return 0;
	}
	GetNodeParent(pRoot->left,pNode);
	GetNodeParent(pRoot->right,pNode);
}

// 求二叉树的镜像 
void Mirror(Node* pRoot)
{
	if (pRoot == NULL)
	{
		return;
    }
	swap(pRoot->left,pRoot->right);
	Mirror(pRoot->left);
	Mirror(pRoot->right);
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值