二叉木の三種類の遍歴方式:再帰、スタック、循環分類:C/C+...
6015 ワード
3つの方法のうち,再帰が最も簡単で,スタックに次いでループが最も面倒である.再帰的な深さが大きすぎるとスタックがオーバーフローします.スタックの方式には追加の補助空間が必要です.ループプログラミングが一番面倒です.
まず、再帰です.
スタック方法:まずループしてノードをスタックに押し込み、それから1つずつポップアップします.
循環:葉の結点の左右のポインタが空の特徴を利用して、葉の結点に直接の後継を設置して、この子の結点を出力した後、更にその直接の後継に戻ります;
前シーケンス、中シーケンスのプログラミングは比較的簡単で、後シーケンスに触れると面倒になることがわかります.
転載先:https://www.cnblogs.com/zclzqbx/p/4687103.html
まず、再帰です.
//
void midPrint_r(TreeNode* root)
{//
if(root==NULL)
return;
if(root->left)
midPrint_r(root->left);
cout<val<right)
midPrint_r(root->right);
}
void prePrint_r(TreeNode* root)
{//
if(root==NULL)
return;
cout<val<left)
prePrint_r(root->left);
if(root->right)
prePrint_r(root->right);
}
void postPrint_r(TreeNode* root)
{//
if(root==NULL)
return;
if(root->left)
postPrint_r(root->left);
if(root->right)
postPrint_r(root->right);
cout<val<
スタック方法:まずループしてノードをスタックに押し込み、それから1つずつポップアップします.
//
void midPrint_l(TreeNode* root)
{
stack s;
TreeNode *cur = root;
while(!s.empty() || cur != NULL)
{
while(cur != NULL)
{
s.push(cur);
cur = cur->left;
}
cur = s.top();
s.pop();
cout<val<right;
}
}
void prePrint_l(TreeNode* root)
{
stack s;
TreeNode *cur = root;
while(!s.empty() || cur != NULL)
{
while(cur != NULL)
{
cout<var<left;
}
cur = s.top();
s.pop();
cur = cur->right;
}
}
void postPrint_l(TreeNode* root)
{
//the original method
/*
We use a prev variable to keep track of the previously-traversed node.
Let’s assume curr is the current node that’s on top of the stack. When
prev is curr‘s parent, we are traversing down the tree. In this case,
we try to traverse to curr‘s left child if available (ie, push left
child to the stack). If it is not available, we look at curr‘s right
child. If both left and right child do not exist (ie, curr is a leaf node),
we print curr‘s value and pop it off the stack.If prev is curr‘s left
child, we are traversing up the tree from the left. We look at curr‘s
right child. If it is available, then traverse down the right child (ie,
push right child to the stack), otherwise print curr‘s value and pop it
off the stack.If prev is curr‘s right child, we are traversing up the tree
from the right. In this case, we print curr‘s value and pop it off the stack.
*/
if(root == NULL)
{
return;
}
stack s;
s.push(root);
TreeNode *cur = NULL;
TreeNode *pre = NULL;
while(!s.empty())
{
cur = s.top();
//left down or right down
if( pre == NULL || pre->left == cur || pre->right == cur)
{// , ,
// ,
if(cur->left != NULL)
{// ,
s.push(cur->left);
}
else if(cur->right != NULL)
{
s.push(cur->right);
}
else
{//
cout<var<left == pre)
{//
if(cur->right != NULL)
{// , ,
s.push(cur->right);
}
else
{
cout<var<right == pre)
{// , ,
cout<var< s;
s.push(root);
TreeNode *cur = NULL;
TreeNode *pre = NULL;
while(!s.empty())
{
cur = s.top();
if(pre == NULL || pre->left == cur || pre->right == cur)
{
if(cur->left != NULL)
{
s.push(cur->left);
}
else if(cur->right != NULL)
{
s.push(cur->right);
}
}
else if(cur->left == pre)
{
if(cur->right != NULL)
{
s.push(cur->right);
}
}
else
{
cout<var<
循環:葉の結点の左右のポインタが空の特徴を利用して、葉の結点に直接の後継を設置して、この子の結点を出力した後、更にその直接の後継に戻ります;
//
void midPrint_m(TreeNode *root)
{
TreeNode *cur = root;
TreeNode *pre = NULL;
while(cur != NULL)
{
if(cur->left == NULL)
{// ,
cout<var<right;
}
else
{
pre = cur->left;
while( pre->right != NULL && pre->right != cur )
{// cur
pre = pre->right;
}
if(pre->right == NULL)
{//
pre->right = cur;
cur = cur->left;
}
else
{
pre->right = NULL;//
cout<var<right;
}
}
}
}
void prePrint_m(TreeNode *root)
{//
TreeNode *cur = root;
TreeNode *pre = NULL;
while(cur != NULL)
{
if(cur->left == NULL)
{
cout<var<right;
}
else
{
pre = cur->left;
while( pre->right != NULL && pre->right != cur )
{
pre = pre->right;
}
if(pre->right == NULL)
{
pre->right = cur;
cout<var<left;
}
else
{
pre->right = NULL;
cur = cur->right;
}
}
}
}
//this is the most difficult algorithm
void reverse_out(TreeNode *from,TreeNode *to)
{
//first reverse from->to
//reverse
TreeNode *cur = from;
TreeNode *post = cur->right;
while(cur != to)
{
TreeNode *tmp = post->right;
post->right = cur;
cur = post;
post = tmp;
}
//already reverse,output list
TreeNode *traversal = cur;
while( cur != from )
{
cout<var<right;
}
cout<var<right;
while(cur != from)
{
TreeNode *tmp = post->right;
post->right = cur;
cur = post;
post = tmp;
}
//restore to's right
to->right = NULL;
}
void postPrint_m(TreeNode *root)
{
TreeNode *newroot = new TreeNode(0);
newroot->left = root;
newroot->right = NULL;
TreeNode *cur = newroot;
TreeNode *pre = NULL;
while(cur != NULL)
{
if(cur->left == NULL)
{
cur = cur->right;
}
else
{
pre = cur->left;
while(pre->right != NULL && pre->right != cur)
{
pre = pre->right;
}
if(pre->right == NULL)
{
pre->right = cur;
cur = cur->left;
}
else
{
pre->right = NULL;
reverse_out(cur->left,pre);
cur = cur->right;
}
}
}
}
前シーケンス、中シーケンスのプログラミングは比較的簡単で、後シーケンスに触れると面倒になることがわかります.
転載先:https://www.cnblogs.com/zclzqbx/p/4687103.html