- 先序遍历树(递归)
- 中序遍历树(递归)
- 后序遍历树(递归)
- 非递归先序遍历
- 非递归中序遍历
- 非递归后序遍历
- 层序遍历
1、先序遍历树(递归)
思路:
- 第一次访问节点便进行打印。
- 递归遍历该节点的左子树
- 递归遍历该节点的右子树
代码如下:
void PreOrder(Node *tree)
{
if (tree != NULL)
{
cout << tree->val << " ";
PreOrder(tree->lTree);
PreOrder(tree->rTree);
}
}
2、中序遍历树(递归)
思路:
- 先递归遍历左子树
- 再打印当前节点
- 最后递归遍历右子树
代码如下:
void InOrder(Node* tree)
{
if (tree != NULL)
{
InOrder(tree->lTree);
cout << tree->val << " ";
InOrder(tree->rTree);
}
}
3、后序遍历树(递归)
思路:
- 先递归遍历左子树
- 再递归遍历右子树
- 最后打印当前节点
代码如下:
void PastOrder(Node* tree)
{
if (tree != NULL)
{
PastOrder(tree->lTree);
PastOrder(tree->rTree);
cout << tree->val << " ";
}
}
4、非递归先序遍历
方法1(从右到左入栈):利用一个栈,首先将根节点入栈,然后当栈不为空时做如下循环
- 获取栈顶元素并打印
- 栈顶元素出栈
- 判断获取到的栈顶元素右子树是否为空,不为空则入栈右节点
- 判断获取到的栈顶元素左子树是否为空,不为空则入栈左节点
代码如下:
void NicePreOrderRTL(Node* tree)
{
stack<Node*> st;
st.push(tree);
while (!st.empty())
{
Node* p = st.top();
cout << p->val << " ";
st.pop();
if (p->rTree != NULL)
{
st.push(p->rTree);
}
if (p->lTree != NULL)
{
st.push(p->lTree);
}
}
}
方法2(从左到右入栈):思路如下:
- 利用一个栈,首先从根节点一直入栈左子树,并不断打印遇到的节点,直到左子树为NULL
- 获取并出栈栈顶元素,对获取到的栈顶元素的右子树做如上操作
- 直到将栈为空,遍历结束
代码如下:
void NicePreOrder(Node* tree)
{
stack<Node*> st;
while (tree != NULL || !st.empty())
{
while(tree)
{
cout << tree->val << " ";
st.push(tree);
tree = tree->lTree;
}
if (!st.empty())
{
tree = st.top();
tree = tree->rTree;
st.pop();
}
}
cout << endl;
}
5、非递归中序遍历
方法1:很显然中序遍历是当第二次访问到某个节点时打印(或其他操作),因此可以利用出栈的次数来进行打印。
- 首先定义一个存储节点访问次数的结构体,此时栈里存储的不光是节点,还有节点对应的出栈次数。如下:
typedef struct stkNode
{
Node* node;//节点
int num;//节点对应的出栈次数
public:
stkNode(Node* n)
{
node = n;
num = 0;
}
}stkNode;
- 首先入栈根节点。
- 获取栈顶元素,判断如果该节点出栈次数,如果为2则打印,然后判断右子树是否为NULL,不为空入栈右子树
- 如果该节点出栈次数不为2则继续将该节点入栈,然后判断该节点左子树是否为NULL,不为空则入栈左子树
- 直到栈空,否则重复上述操作
代码如下:
void NiceInOrdernum(Node* tree)
{
if (tree == NULL)
{
return;
}
stack<stkNode> st;
st.push(tree);
while (!st.empty())
{
stkNode stk = st.top();
st.pop();
if (++stk.num == 2)
{
cout << stk.node->val << " ";
if (stk.node->rTree != NULL)
{
st.push(stkNode(stk.node->rTree));
}
}
else
{
st.push(stk);
if (stk.num == 1 && stk.node->lTree != NULL)
{
st.push(stkNode(stk.node->lTree));
}
}
}
cout << endl;
}
方法2:该方法和从左到右入栈先序非递归遍历相似,只是在入栈左子树的过程中不打印所遇到的节点,而是等到出栈的时候再打印。思路如下
- 利用一个栈,首先从根节点一直入栈左子树,直到左子树为NULL。
- 获取并出栈栈顶元素并打印,对获取到的栈顶元素的右子树做如上操作
- 直到将栈为空,遍历结束
代码如下:
void NiceInOrder(Node* tree)
{
stack<Node*> st;
while (tree != NULL || !st.empty())
{
while (tree != NULL)
{
st.push(tree);
tree = tree->lTree;
}
if (!st.empty())
{
tree = st.top();
st.pop();
cout << tree->val << " ";
tree = tree->rTree;
}
}
cout << endl;
}
6、非递归后序遍历
方法1:后序遍历和中序遍历一样,也可以利用出栈次数的方式来做,只不过后序遍历是第三次出栈进行打印。
代码如下:
void NiceLastOrdernum(Node* tree)
{
if (tree == NULL)
{
return;
}
stack<stkNode> st;
st.push(tree);
while (!st.empty())
{
stkNode stk = st.top();
st.pop();
if (++stk.num == 3)
{
cout << stk.node->val << " ";
}
else
{
st.push(stk);
if (stk.num == 1 && stk.node->lTree != NULL)
{
st.push(stk.node->lTree);
}
else if (stk.num == 2 && stk.node->rTree != NULL)
{
st.push(stk.node->rTree);
}
}
}
cout << endl;
}
7、层序遍历
层序遍历顾名思义就是一层一层的打印。
第一步:首先我们完成一个小目标,打印某一层的元素。可以利用递归的方式进行。每向下递归一层则离我们的目标层近一层。直到距目标层为1的时候打印元素,即为第k层的元素。
代码如下:
void PrintLevel_K(Node* tree, int k)
{
if (tree == NULL || k < 0)
{
return;
}
if (k == 0)
{
cout << tree->val << " ";
}
else
{
PrintLevel_K(tree->lTree, k - 1);
PrintLevel_K(tree->rTree, k - 1);
}
}
第二步:求树的深度,即树有多少层。
思路:树的深度即为左子树和右子树深度较大的深度加上1,因此我们也可以利用递归来做。
代码如下:
int Depth(Node* tree)
{
if (tree == NULL)
{
return 0;
}
else
{
return max(Depth(tree->lTree), Depth(tree->rTree)) + 1;
}
}
第三步:层序打印。
思路:我们已经知道了树有多少层,也可以对树的某一层进行打印。因此循环打印每一层即可
代码如下:
void LevelPrint(Node* tree)
{
int depth = Depth(tree);
for (int i = 0; i < depth; i++)
{
PrintLevel_K(tree, i);
cout << endl;
}
}