二叉树的先序遍历使用递归很简单,代码如下:
void preOrder(TNode* root)
{
if (root != NULL)
{
Visit(root);
preOrder(root->left);
preOrder(root->right);
}
}
先访问跟节点,然后访问左节点,再访问右节点。如果不用递归,那该怎么做呢?仔细看一下递归程序,就会发现,其实每次都是走树的左分支(left),直到左子树为空,然后开始从递归的最深处返回,然后开始恢复递归现场,访问右子树。
其实过程很简单:一直往左走 root->left->left->left…->null,由于是先序遍历,因此一遇到节点,便需要立即访问;由于一直走到最左边后,需要逐步返回到父节点访问右节点,因此必须有一个措施能够对节点序列回溯。有两个办法:
1.用栈记忆:在访问途中将依次遇到的节点保存下来。由于节点出现次序与恢复次序是反序的,因此是一个先进后出结构,需要用栈。
2.节点增加指向父节点的指针:通过指向父节点的指针来回溯
方法一,直接用栈模拟递归。次将节点压入栈,然后弹出,压右子树,再压入左子树,在遍历过程中,遍历序列的右节点依次被存入栈,左节点逐次被访问。同一时刻,栈中元素为m-1个右节点和1个最左节点,最高为h。所以空间也为O(h);每个节点同样被压栈一次,弹栈一次,访问一次,时间复杂度O(n)
01 |
#include <stdlib.h> |
02 |
#include <stdio.h> |
03 |
#include <iostream> |
04 |
#include <stack> |
05 |
06 |
using namespace std;
|
07 |
08 |
/* 二叉树节点 */ |
09 |
struct node
|
10 |
{ |
11 |
int data;
|
12 |
struct node* left;
|
13 |
struct node* right;
|
14 |
}; |
15 |
16 |
struct node* newNode( int data)
|
17 |
{ |
18 |
struct node* node = new struct node;
|
19 |
node->data = data;
|
20 |
node->left = NULL;
|
21 |
node->right = NULL;
|
22 |
return (node);
|
23 |
} |
24 |
25 |
// 非递归的方式先序遍历二叉树 |
26 |
void iterativePreorder(node *root)
|
27 |
{ |
28 |
if (root == NULL)
|
29 |
return ;
|
30 |
31 |
// 根节点入栈
|
32 |
stack<node *> nodeStack;
|
33 |
nodeStack.push(root);
|
34 |
35 |
while (nodeStack.empty() == false )
|
36 |
{
|
37 |
// 访问根节点
|
38 |
struct node *node = nodeStack.top();
|
39 |
printf ( "%d " , node->data);
|
40 |
nodeStack.pop();
|
41 |
42 |
// 不为空的话则入栈
|
43 |
if (node->right)
|
44 |
nodeStack.push(node->right);
|
45 |
if (node->left)
|
46 |
nodeStack.push(node->left);
|
47 |
}
|
48 |
} |
49 |
50 |
//测试 |
51 |
int main()
|
52 |
{ |
53 |
/* 创建以下的树
|
54 |
10
|
55 |
/ \
|
56 |
8 2
|
57 |
/ \ /
|
58 |
3 5 2
|
59 |
*/
|
60 |
struct node *root = newNode(10);
|
61 |
root->left = newNode(8);
|
62 |
root->right = newNode(2);
|
63 |
root->left->left = newNode(3);
|
64 |
root->left->right = newNode(5);
|
65 |
root->right->left = newNode(2);
|
66 |
iterativePreorder(root);
|
67 |
return 0;
|
68 |
} |
方法二 同样是使用栈,每次都将遇到的节点压入栈,当左子树遍历完毕后才从栈中弹出最后一个访问的节点,访问其右子树。在同一层中,不可能同时有两个节点压入栈,因此栈的大小空间为O(h),h为二叉树高度。时间方面,每个节点都被压入栈一次,弹出栈一次,访问一次,复杂度为O(n)
01 |
void iterativePreorder2(node *root) {
|
02 |
stack<node *> s;
|
03 |
while ((root != NULL) || !s.empty()) {
|
04 |
if (root != NULL) {
|
05 |
printf ( "%d " , root->data);
|
06 |
s.push(root); // 先序就体现在这里了,先访问,再入栈
|
07 |
root = root->left; // 依次访问左子树
|
08 |
} else {
|
09 |
root = s.top(); // 回溯至父亲节点. 此时根节点和左子树都已访问过
|
10 |
s.pop();
|
11 |
root = root->right;
|
12 |
}
|
13 |
}
|
14 |
} |
原文:http://www.acmerblog.com/iterative-preorder-traversal-5853.html
相关推荐
用C++写的,包括二叉树的构建,二叉树的先序遍历、中序遍历和后序遍历非递归算法。
用C++写的二叉树先序遍历、中序遍历和后序遍历非递归算法
非递归实现通常使用栈: ```python def pre_order_traversal_iterative(root): if not root: return stack, output = [root], [] while stack: node = stack.pop() if node is not None: output.append(node....
在非递归先序遍历中,我们可以使用栈来存储树的节点,以便遍历树的所有节点。 (2)中序遍历 中序遍历是一种遍历二叉树的方法,它首先遍历树的左子树,然后访问树的根节点,最后遍历树的右子树。在非递归中序遍历...
用户以先序遍历的方式键入二叉树各结点的数据域值(字符型),程序建立二叉树,然后分别用递归和非递归算法对二叉树进行遍历。每访问一个结点即打印该结点的数据域值。
编写先序遍历二叉树的非递归算法程序,要求: (1)以二叉链表建立二叉树。 (2)输出遍历的结点序列。 (3)有实例验算。
本文将详细介绍二叉树的先序遍历非递归算法,包括其原理、实现代码和相关知识点。 知识点1:二叉树的概念 二叉树是一种特殊的树形结构,每个节点最多有两个孩子节点:左孩子和右孩子。二叉树可以用于表示各种树形...
包含一下方法: 1.通过一个数组来构造一颗...6.使用非递归 先序遍历一棵二叉树 7.使用非递归 中序遍历一棵二叉树 8.使用非递归 后序遍历一棵二叉树 PS:代码为C++代码 可以直接下载使用!!! PS2:每句代码都有详细注释
根据给定文件的信息,本文将详细介绍二叉树的创建及三种基本的递归遍历方法:先序遍历、中序遍历和后序遍历。 ### 一、二叉树的基本概念 二叉树是一种非线性数据结构,每个节点最多有两个子节点,通常称为左子节点...
二叉树的几种操作,包括递归先序建立二叉树、先序遍历、中序遍历、后序遍历、非递归的各种遍历、计算叶子节点数目和所有节点数目,使用队列实现二叉树的层次遍历.zip
#### 先序遍历非递归算法 先序遍历(也称为前序遍历)的顺序是“根-左-右”,即先访问根节点,然后依次访问左子树和右子树。在非递归实现中,我们通常使用一个栈来帮助完成这一过程: ```c void PreOrderUnrec...
数据结构二叉树链式结构的前序遍历,中序遍历,后序遍历用递归的方法,层级遍历采用队列结构
在深入探讨C语言实现二叉树的前序遍历(非递归)之前,我们首先应当理解何为二叉树以及前序遍历的基本概念。 ### 二叉树简介 二叉树是一种特殊的树形数据结构,每个节点最多有两个子节点,通常称为左子节点和右子...
按先序遍历的扩展序列建立二叉树的二叉链表存储结构,实现二叉树先序、中序、后序遍历的递归算法,实现二叉树中序遍历的非递归算法,实现二叉树层次遍历的非递归算法(要求使用顺序队列,调用顺序队列基本操作...
非递归先序遍历是一种不依赖递归函数来遍历二叉树的方法,它通过使用栈(List)来保存待处理的节点,从而避免了递归带来的栈溢出问题。 在这个实例中,我们首先创建了一个名为`Program`的类,并在`Main`方法中初始...
C,二叉树中的非递归的先序遍历 (附带算法说明书word)利用栈数据结构实现二叉树中的非递归的先序遍历。
数据结构基于C++语言程序开发的树的非递归先序遍历 if (p->rchild != NULL)/* 右孩子入栈 */ { top++; stack[top] = p->rchild; } if (p->lchild != NULL)/* 左孩子入栈 */ { top++; stack[top] = p->...
- **非递归实现**:同样使用栈,但不同于先序遍历,中序遍历在遇到右子节点时不会立即访问,而是将其压入栈中,直到遍历到其左子树的叶子节点才会回溯到根节点。 3. **后序遍历**: - **递归实现**:先遍历左子树...
本文将深入探讨标题所提及的"二叉树先序遍历",并结合描述中的"随机建树及先序演示程序"进行详细讲解。 首先,我们来理解什么是二叉树。二叉树是由节点(或称为顶点)和边构成的,每个节点最多有两个子节点,分别被...