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;
}