可能长代码大多人只会匆匆瞟一眼然后COPY一下看看输出结果吧。那就分解成短代码来一块一块详细解释一下吧。不过一般很复杂的程序都是由大量的各种简单的知识点组成的。
现在在网上看到的我需要的代码,如果有时间的话我会把它整个抄下来然后用笔去一行一行推。问我哪里来的时间.....当然是那些无聊的选修课了.......
void Tree::Non_Recursive_PreOrder(TreeNode*T) //protected非递归先序遍历
{
/*——————————————————————————
首先进行p的输出。存储的内容基本上是右结点。
遍历左边缘不断输出,然后转到右结点入栈,继续
左边缘不断输出。等到再无左边缘的时候逆向输出
所有右孩子。
———————————————————————————*/
stack<TreeNode*> s;
TreeNode *p=T,*q;
s.push(p);//把Root推入栈内
while(!s.empty())//如果s不空
{
cout<<p->data;
q=p->RightChild;
if(q)s.push(q); //如果q(p的右孩子)不空则将q推入栈
p=p->LeftChild;
if(!p) //如果p(p的左孩子)为空则回到(p的右孩子)
{
p=s.top();
s.pop();
}//if
}//while
}//Non_recursive_PreOrder
非递归先序遍历实现的步骤:
①首先定义一个<TreeNode*>类型的栈。
②定义两个指针变量p和q,p等于参数,即树的根节点;q用来存储右孩子。然后把p入栈。
③一旦栈不空
a.输出p的数值并看它的右孩子存不存在,存在就把它的右孩子推入栈内。
b.然后看左孩子是否为空,若为空则栈的首元素出栈(即最邻近的一个树节点的右孩子)赋值给p。
void Tree::Non_Recursive_IndexOrder(TreeNode*T) //protected非递归中序遍历
{
/*————————————————————————————
首先不断遍历左边缘但不输出只入栈,
直到碰到NULL后(此时p=NULL)返回父结点输出父结点。
然后转到右结点入栈,继续遍历左边缘不输出
只入栈。一直编立到某个度为0的右结点的右孩子的时候
结束一支分支的遍历。
另一支分支的遍历相同。这一支分支的遍历
结束后中序遍历结束。
—————————————————————————————*/
stack<TreeNode*> s;
TreeNode *p=T;
s.push(NULL);
while(1)
{
while(p)
{
s.push(p); //栈是回溯法的主要工具
p=p->LeftChild;
}//while 遍历左边缘直到NULL
if(!s.top())break;//如果栈到达栈底则跳出
p=s.top();//p=NULL的时候返回其父结点或爷结点
s.pop();//弹出父结点
cout<<p->data;//输出父结点
p=p->RightChild;//调用父结点的右孩子
}//while
}//Non_recursive_IndexOrder
非递归中序遍历步骤:
①定义栈,树指针结点,并将 NULL push进栈。如果不push个NULL的话 用while(!s.empty())会直接跳出函数,
②循环,如果p不为空则将p入栈然后p等于它的左孩子。一直遍历到 'a' 的左孩子的位置(即NULL)。
③跳出无限循环的条件,如果到达了栈底(NULL)就跳出无限循环。
④这个时候p的值为NULL,所以获得栈首元素(父节点'a')然后出栈。
⑤输出当前p的值。('a')
⑥p访问当前结点的右孩子。(如果有右孩子则会沿着右孩子的左孩子遍历并入栈,如果右孩子为空则会继续往上遍历父节点。)
void Tree::Non_Recursive_PostOrder(TreeNode*T) //protected非递归后序遍历
{
/*——————————————————————————
先进行左边缘遍历,入栈,并记载访问次数为1(tag=0)。
直到p=NULL,然后返回父结点,父结点访问次数为2(tag=1)。
p转到父结点的右孩子。
重复以上步骤。
如果栈顶结点被第三次访问,则输出该结点,弹出。
———————————————————————————*/
stack<TreeNode*> s;//用于存储树结点
stack<bool>s1;//用于存储结点暂离状态
TreeNode *p=T;
s.push(NULL);//没有此句函数直接结束
while(1)//如果s不空
{
while(p)
{
s.push(p);
s1.push(false);
p=p->LeftChild;
}//while 用于存储左边缘树结点,全部暂离
if(s1.top())
{
p=s.top();
s1.pop();
s.pop();
cout<<p->data;
p=NULL;
}//if 第二次访问结点结点已待命,将结点和状态全部弹出,输出结点。令p=NULL,避免第四次读取结点。
else
{
s1.pop();
s1.push(true);
p=s.top()->RightChild;
}//else 如果结点是暂离,让其准备,当第二次碰见它时就输出。此时访问右孩子
if(!s.top())break;//如果栈到达栈底则跳出
}//while
}//Non_recursive_PostOrder
(第一次访问结点入栈状态为false,第二次访问结点将状态改成true,第三次访问结点输出结点数据,避免出现第四次访问结点。)
(为什么是这样?访问父节点的时候设置状态为false,访问左孩子回到父节点状态改成true,从右孩子回到父节点的时候输出父节点,共三次。)
非递归后序遍历的步骤:
①定义两个栈,第一个栈类型为<TreeNode*> 第二个栈类型为<bool>,以及树节点指针p,将NULL push进栈。
②循环,如果p不为空,则(树节点栈)p入栈,(状态栈)false入栈,表示还没进行第二次访问。然后不断遍历左孩子。
③如果状态栈首元素为true(此时为第三次访问树节点),获得栈首树节点然后输出数据,出栈。
否则状态栈首元素为false(此时为第二次访问树节点),将状态改成false,然后访问其右孩子。
④如果到达栈底(NULL)就跳出无限循环。