二叉树学习笔记

1 二叉树的遍历

二叉树是树的一种特殊结构,也是一种极为重要的树,二叉树最重要的操作是遍历,即按照一定的顺序访问树中的所有节点,常见的遍历方式有:

  • 前序遍历
  • 中序遍历
  • 后序遍历

 对遍历来说,最容易想到的方式就是递归,递归代码简单,但是效率不高,需要的栈空间比较大,非递归的方法代码较为复杂,不过效率较高。

1.1 前序遍历

递归实现:

void preOrderVisit(binaryTreeNode *pNode)
{
	if (pNode)
	{
		printf("%d\t", pNode->m_nValue);
		preOrderVisit(pNode->m_pLeft);
		preOrderVisit(pNode->m_pRight);
	}
}

非递归实现:

前序遍历要求先访问根节点,再访问其左右节点,处理过程如下:

        1)从根节点p开始,将p入栈;

        2)访问栈顶元素,并做出栈操作,若其右节点不为空,将右节点入栈;若左节点不为空,将左节点入栈;

        3)重复第2步,直到栈为空;

代码如下:

void preOrderVisit_nonRecursively(binaryTreeNode *pNode)
{
	if (pNode == NULL)
		return;

	binaryTreeNode *pTemp;
	stack<binaryTreeNode*> nodes;
	nodes.push(pNode);

	while (!nodes.empty())
	{
		pTemp = nodes.top();
		nodes.pop();
		printf("%d\t", pTemp->m_nValue);

		if (pTemp->m_pRight)
		{
			nodes.push(pTemp->m_pRight);
		}
		if (pTemp->m_pLeft)
		{
			nodes.push(pTemp->m_pLeft);
		}
	}
}

 

1.2 中序遍历

递归实现:

void InOrderVisit(binaryTreeNode *pNode)
{
	if (pNode)
	{
		InOrderVisit( pNode->m_pLeft);
		printf("%d\t", pNode->m_nValue);
		InOrderVisit( pNode->m_pRight);
	}
}

非递归实现:

处理过程如下:

1)从根节点p开始,将p入栈,若p的左节点不为空,则将左节点入栈,并令p = p->m_pLeft,直到左节点为空;

2)访问栈顶元素,做出栈处理,若其右节点不为空,将右节点入栈,并令当前指针等于右节点;

3)重复上述过程,直到栈为空;

代码如下:

void InOrderVisit_nonRecursively(binaryTreeNode * pNode)
{
	if (pNode == NULL)
		return;

	binaryTreeNode *pTemp = pRoot;
	stack<binaryTreeNode*> nodes;

	while (pTemp || !nodes.empty())
	{
		while (pTemp)
		{
			nodes.push(pTemp);
			pTemp = pTemp->m_pLeft;
		}

		pTemp = nodes.top();
		nodes.pop();
		printf("%d\t", pTemp->m_nValue);

		pTemp = pTemp->m_pRight;
	}

1.3 后序遍历

递归实现:

void posOrdertVisit(binaryTreeNode *pNode)
{
	if (pNode)
	{
		posOrdertVisit(pNode->m_pLeft);
		posOrdertVisit(pNode->m_pRight);

		printf("%d\t", pNode->m_nValue);
	}
}

非递归实现:

处理过程如下:

1)从根节点p开始,将p入栈;

2)取栈顶元素,若其左节点、右节点均为空,则可以直接访问该元素;或者该节点的左右子节点都已访问过,则也可以直接访问该元素;若非上述两种情况,则依次将右子节点、左子节点入栈;

3)重复第2步,直到栈为空;

代码如下:

void posOrdertVisit_nonRecursively(binaryTreeNode * pNode)
{
	if (pNode == NULL)
		return;

	binaryTreeNode *pCurrentNode;
	binaryTreeNode *pLastNode = NULL;
	stack<binaryTreeNode*> nodes;
	nodes.push(pNode);

	while (!nodes.empty())
	{
		pCurrentNode = nodes.top();
		if ((pCurrentNode->m_pLeft == NULL && pCurrentNode->m_pRight == NULL) ||
			(pLastNode != NULL && (pLastNode == pCurrentNode->m_pLeft || pLastNode == pCurrentNode->m_pRight)))
		{
			nodes.pop();
			printf("%d\t", pCurrentNode->m_nValue);
			pLastNode = pCurrentNode;
		}
		else
		{
			if (pCurrentNode->m_pRight)
			{
				nodes.push(pCurrentNode->m_pRight);
			}
			if (pCurrentNode->m_pLeft)
			{
				nodes.push(pCurrentNode->m_pLeft);
			}
		}
	}
}

2 二叉树重建

这里是根据前序遍历和中序遍历来重建二叉树,且假设遍历结果中没有重复的元素。

递归实现:

int rebuildBinaryTree(int *pPreOrder, int *pInOrder, int treeLen, binaryTreeNode **pRoot)
{
	//边界条件检查
	if ( pPreOrder == NULL || pInOrder == NULL || pRoot == NULL || treeLen <= 0)
		return 0;

	//构建根节点
		binaryTreeNode *pNode;
		if (!(pNode = (binaryTreeNode *)malloc(sizeof(binaryTreeNode))))
			return 0;
		pNode->m_nValue = *pPreOrder;
		pNode->m_pLeft = pNode->m_pRight = NULL;
		*pRoot = pNode;

	if (treeLen == 1 ) 
	{
		if (*pPreOrder == *pInOrder)
		{
			//*pRoot = pNode;
			return 1;
		}
		else
		{
			return 0;
		}
	}
	

	//划分左右子树
	int i;
	int built = 0;
	int *pRootInOrder = pInOrder;
	//int *pEndInOrder = pInOrder + treeLen - 1;
	/*while (pRootInOrder < pEndInOrder && *pRootInOrder != *pPreOrder)
		++ pRootInOrder;

	if (pRootInOrder == pEndInOrder && *pRootInOrder != *pPreOrder)
		return 0;*/
	for (i = 0; i < treeLen; i++, pRootInOrder++)
	{
		if (*pRootInOrder == *pPreOrder)
		{
			int leftLength = pRootInOrder - pInOrder;
			int rightLength = treeLen - leftLength - 1;

			if (leftLength && rightLength) 
			{
				if (isValid(pPreOrder + 1, pInOrder, leftLength,leftLength) &&
					isValid(pPreOrder + leftLength + 1, pInOrder + leftLength + 1, rightLength, rightLength))
				{
					rebuildBinaryTree(pPreOrder + 1, pInOrder, leftLength, &(pNode->m_pLeft));
					rebuildBinaryTree(pPreOrder + leftLength + 1, pInOrder + leftLength + 1, rightLength, &(pNode->m_pRight));
					built = 1;
				}
			}
			else if (leftLength && rightLength <= 0)
			{
				if (isValid(pPreOrder + 1, pInOrder, leftLength,leftLength))
				{
					rebuildBinaryTree(pPreOrder + 1, pInOrder, leftLength, &(pNode->m_pLeft));
					built = 1;
				}
			}
			else if (leftLength <= 0 && rightLength)
			{
				if (isValid(pPreOrder + leftLength + 1, pInOrder + leftLength + 1, rightLength, rightLength))
				{
					rebuildBinaryTree(pPreOrder + leftLength + 1, pInOrder + leftLength + 1, rightLength, &(pNode->m_pRight));
					built = 1;
				}
			}
		}
	}
	return built?1 : 0;
}



 






 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值