本文介绍二叉树的前序,中序和后序遍历,采用递归和非递归两种方式实现。除此之外,还介绍了对二叉树按层遍历的方法。对树的前中后序遍历是深度优先搜索的策略,因此用栈实现。对树的按层遍历是广度优先搜索,因此采用队列实现。
树的前序,中序和后序遍历,都是针对父节点而言的。
二叉树的定义
下面给出二叉树的定义:
struct Tree
{
int value;
Tree* pLeft;
Tree* pRight;
};
typedef Tree* binaryTree;
递归实现前序,中序和后序遍历
递归实现前序,中序和后序遍历思路相同。前序遍历如果当前节点不为空,就打印该节点的数值,然后对左子树和右子数分别递归调用该函数。递归调用要注意停止的条件。
/* 递归实现前序遍历 */
void preOrderRecur(binaryTree T)
{
if(T == NULL)
return;
printf("%d ",T->value);
preOrderRecur(T->pLeft);
preOrderRecur(T->pRight);
}
/* 递归实现中序遍历 */
void inOrderRecur(binaryTree T)
{
if(T == NULL)
return;
inOrderRecur(T->pLeft);
printf("%d ", T->value);
inOrderRecur(T->pRight);
}
/* 递归实现后续遍历 */
void posOrderRecur(binaryTree T)
{
if(T == NULL)
return;
posOrderRecur(T->pLeft);
posOrderRecur(T->pRight);
printf("%d ", T->value);
}
二叉搜索树的前,中,后序遍历
对于二叉搜索树前,中,后序遍历的结果分别有各自的特点:
对于下图
前序遍历结果为:15-6-3-2-4-7-13-9-18-17-20;
中序遍历结果为:2-3-4-6-7-9-13-15-17-18-20;
后序遍历结果为:2-4-3-9-13-7-6-17-20-18-15;
中序遍历的结果最明显,使得二叉查找树呈从小到大的状态排序。这个结果很有用,对于二叉树中查找第K大的元素,转为排序的链表。
前序遍历的结果特点是,第一个数15将整个二叉树分成两部分,一部分是6-3-2-4-7-13-9都小于15,另一部分18-17-20都大于15。对于这每一个小部分右可以这样分析,6-3-2-4-7-13-9由最前面的数6分成两个部分,一部分是3-2-4是小于6的部分,另一部分是7-13-9是大于6的部分。对于3-2-4可以继续这样分析,第一个数3将其分为两个部分。后面分析是一样的不在赘述。
后续遍历的特点与前序相似,做一点小的改变就行。
非递归实现先序遍历
递归方式实现遍历,递归就相当于一个栈,用函数栈来保存了数据,因此,非递归的方式就是用栈来现实遍历。
先序遍历的非递归实现经过一下步骤:
(1)将根节点压入栈;
(2)弹出栈顶元素,打印栈顶元素的值,如果该元素的右子树不为空,则先将右子数压入栈,如果该元素的左子树也不为空,则将该元素的左子树也压入栈;
(3)重复步骤2直到栈为空。
该方法与图的深度优先搜索是一样的,类似的实现。
/* 非递归实现先序遍历 */
void preOrderUnRecur(binaryTree T)
{
if(T == NULL)
return;
stack<int> S; //定义一个栈
S.push(T); //压入根节点
while(!S.empty())
{
//弹出栈顶元素
binaryTree tempNode = S.top();
S.pop();
printf("%d ", tempNode->value);
//先压入右子树,后压入左子树
if(tempTree != NULL)
S.push(tempNode->pRight);
if(tempTree != NULL)
s.push(tempNode->pLeft);
}
}
非递归实现中序遍历
非递归实现中序遍历,经过以下步骤:
(1)定义一个当前节点,将根节点指针赋给当前节点;
(2)如果当前节点不为空,就将当前节点压入栈,并将当前节点更新为其左子树;
(3)如果当前节点为空,就弹出栈顶元素,并打印该元素值。然后将当前节点更新为该元素值的右子树;
(4)一直重复(2)或(3)直到栈为空而且当前元素值也为空。
/* 非递归实现中序遍历 */
void inOrderUnrecur(binaryTree T)
{
if(T == NULL)
return;
stack<int> S;
binaryTree tempNode = T;
while(!S.empty() && tempNode == NULL)
{
if(tempNode->pLeft != NULL)
{
S.push(tempNode->pLeft);
tempNode = tempNode->pLeft;
}
else
{
tempNode = S.top();
printf("%d ",tempNode->value);
S.pop();
tempNode = tempNode.pRight;
}
}
}
非递归实现后序遍历
非递归实现后序遍历,经过以下步骤:
(1)定义两个栈S1和S2,S1作为零时存储,S2作为最终输出数据存储,将根节点指针压入S1;
(2)从S1总弹出栈顶元素,将该元素压入S2,将S1不为空的左右子树压入S1;
(3)重复2过程直到S1为空为止;
(4)最后依次弹出S2的数据,并打印就是后序遍历的结果。
/* 非递归实现后序遍历 */
void posOrderUnrecur(binaryTree T)
{
if(T == NULL)
return;
stack<int> S1;
stack<int> S2;
binaryTree cur;
S1.push(T);
while(!S1.empty())
{
cur = S1.top();
S1.pop();
S2.push(cur);
if(cur->left != NULL)
S1.push(cur->left);
if(cur->right != NULL)
S1.push(cur->right);
}
while(!S2.empty())
{
cur = S2->top();
S2.pop();
printf("%d\n", S2->value);
}
}
按层遍历二叉树
按层遍历就是二叉树的广度优先搜索
(1)将二叉树的根从头部压入队列
(2)从队列尾部弹出一个元素,打印该元素值,然后将如果该元素左子树不为空,则将该元素的左子树从头部压入队列,右子树相同的操作;
(3)重复过程2直到队列为空。
/* 按层遍历二叉树 */
//用一个队列保存数据
void floorOrder(binaryTree T)
{
if(T == NULL)
return;
deque<int> Q;
Q.push_back(T);
while(!Q.empty())
{
binaryTree tempNode = Q.front();
printf("%d ", tempNode->value);
if(tempNode->pLeft != NULL)
Q.push_back(tempNode.pLeft);
if(tempNode->pRight != NULL)
Q.push_back(tempNode.pRight);
Q.pop_front();
}
}