树结点的声明
struct BinaryNode
{
char element;
BinaryNode* left;
BinaryNode* right;
BinaryNode()
{
element = ' ';
left = right = NULL;
}
};
创建一棵二叉树
BinaryNode * creatBinaryTree (string&s)
{
if (s.empty())
return NULL;
size_t n = s.size();
BinaryNode* p = new BinaryNode[n];
for (int i = 0; i < n; ++i)
{
p[i].element = s[i];
if ( (2*i+1) < n )
p[i].left = &p[2*i+1];
if ( (2*i+2) < n )
p[i].right = &p[2*i+2];
}
return p;
}
输出二叉树
enum mode{preR,preNr, inR, inNr, postR, postNr};
void displayBinaryTree(BinaryNode*t, enum mode& m)
{
switch(m)
{
case preR:
preOrderTraverse_Recursive(t);
break;
case preNr:
preOrderTraverse_nonRecursive(t);
break;
case inR:
inOrderTraverse_Recursive(t);
break;
case inNr:
inOrderTraverse_nonRecursive(t);
break;
case postR:
postOrderTraverse_Recursive(t);
break;
case postNr:
postOrderTraverse_nonRecursive(t);
break;
default:
;
}
}
一.先序遍历
1.递归算法
void preOrderTraverse_Recursive( BinaryNode *t)
{
if (t)
{
cout << t->element << endl;
preOrderTraverse_Recursive(t->left);
preOrderTraverse_Recursive(t->right);
}
}
2.非递归算法
思路::在先序遍历中,由于根节点首先被访问,而且由根结点可以同时得到左右孩子结点的信息,因此在访问过程中,可以在访问根节点的同时将根节点从栈中删除,并且将根节点的左右孩子按照右孩子,左孩子的顺序入栈。
void preTraverse_nonRecursive( BinaryNode *t)
{
stack<TreeNode*>s;
TreeNode* p = root;
s.push(p);
while (!s.empty())
{
p = s.top();
s.pop();
if (p)
{
cout<<p->element<<endl;
s.push(p->right);
s.push(p->left);
}
}
}
二.中序遍历
1.递归算法
void inOrderTraverse_Recursive( BinaryNode *t)
{
if (t)
{
inOrderTraverse_Recursive(t->left);
cout << t->element << endl;
inOrderTraverse_Recursive(t->right);
}
}
2.非递归算法
思路1和思路2的主要区别是思路1会将空指针压入栈中,而思路2则不会,因此思路1需要将空指针弹出栈
//思路1
void inOrderTraverse_nonRecursive( BinaryNode *t)
{
stack<BinaryNode*>s;
BinaryNode* p = t ;
s.push(p);
while ( !s.empty() )
{//p表示栈顶元素
p = s.top();
while ( p )
{//向左走到尽头,最后压入的一定是空指针
p = p->left;
s.push(p);
}
s.pop();//空指针出栈
if (!s.empty())
{
p = s.top();
s.pop();
cout << p->element << endl;
s.push( p->right );
}
}
}
void inOrderTraverse_nonRecursive( BinaryNode *t)
{//思路2
stack<BinaryNode*>s;
BinaryNode* p = t ;
while ( p || !s.empty() )
{//p指向的是下一个需要被访问的结点
if ( p )
{
s.push(p);
p = p->left;
}
else
{//p为null,栈非空
p = s.top();
s.pop();//根指针退栈,遍历右子树
cout << p->element << endl;
p = p->right;
}
}
}
三.后序遍历
1.递归算法
void postOrderTraverse_Recursive( BinaryNode *t)
{
if (t)
{
postOrderTraverse_Recursive(t->left);
postOrderTraverse_Recursive(t->right);
cout << t->element << endl;
}
}
2.非递归算法
思路:按照根节点,右孩子结点,左孩子结点的顺序依次入栈。如果一个结点没有左右孩子结点,则该结点可被访问,同时该结点出栈。如果一个结点有左右孩子结点,但是其孩子结点已经被访问,则该结点也可以被访问。因此需要设置一个变量preNode存放上次被访问的结点。
void postOrderTraverse_nonRecursive( BinaryNode *t)
{
stack<BinaryNode*>s;
BinaryNode* p = t ;
BinaryNode* preNode = t;
if (p)
s.push(p);
while (!s.empty())
{
p = s.top();
if ( (p->left == NULL && p->right==NULL)
|| (preNode == p->left || preNode == p->right) )
{
cout << p->element << endl;
s.pop();
preNode = p;
}
else
{
if (p->right)
s.push(p->right);
if (p->left)
s.push(p->left);
}
}
}
上图为反映了后序遍历时数据出栈入栈的情况。结点d因为左右孩子都为空,因此可以访问,访问完成后出栈,结点b的左右孩子因为都被访问过,因此也可以被访问,此时b的前一个访问结点是结点e,即它的右结点。