前序遍历
实现思路:
前序遍历,先打印根结点,再打印左右孩子,我们循环遍历各个结点时,要做到先出栈根节点,再将根节点右孩子和左孩子入栈,等到下一轮循环时,就先出栈其左孩子,再将左孩子的右左孩子入栈,直到叶子结点,按照左中右的顺序遍历完所有的结点。
void NicePreOrder(BinaryTree *ptr)//非递归进行前中后序遍历
{
assert(ptr != NULL);
stack* s;
Init_stack(s);
Push_stack(s, ptr);//
while (ptr!=NULL)
{
BinaryTree* p = Top(s); Pop_stack(s);
printf("%c ", p->data);
if (ptr->rightchild != NULL)
Push_stack(s, ptr->rightchild);
if (ptr->leftchild != NULL)
{
Push_stack(s,ptr->leftchild);
}
}
}
中序遍历
核心思想,遍历顺序左中右,那么必须先找到最左端的根节点,然后将该结点出栈,打印该结点的值,将该结点的右孩子入栈,若该结点右孩子结点为null,则接着出栈,否则,指向该结点的右孩子,进行下一轮的出栈入栈操作。
void NiceInOrder(BinaryTree *ptr)
{
assert(ptr != NULL);
stack* s;
Init_stack(s);
while (ptr != NULL&&!IsEmpty_stack(s))
{
while (ptr != NULL)
{
Push_stack(s, ptr);
ptr = ptr->leftchild;
}
BinaryTree* p = Top(s); Pop_stack(s);
printf("%c ", p->data);
ptr = ptr->rightchild;
}
}
- 后序遍历
核心思想:后序遍历的顺序为:左右中,先找到最左边的结点,然后出栈,若该结点的右孩子为空,或已经出过栈,那么打印该结点,否则,将该结点继续入栈,查找其右孩子,在对该孩子进行循环遍历。其中,引入tag变量,对打印过的结点做一个记录,防止重复打印。
void NicePastOrder(BinaryTree *ptr)
{
assert(ptr != NULL);
stack* s;
Init_stack(s);
BinaryTree* tag = NULL;
while (!IsEmpty_stack(s) && ptr != NULL)
{
while (ptr != NULL)
{
Push_stack(s, ptr);
ptr = ptr->leftchild;
}
BinaryTree* p = Top(s); Pop_stack(s);
if (ptr->rightchild == NULL || ptr->rightchild == tag)
{
printf("%c ", ptr->data);
tag = ptr;
ptr = NULL;
}
else
{
Push_stack(s, ptr);
ptr = ptr->rightchild;
}
}
}
以上三个非递归遍历中,用到了栈,自己编写一个小的栈函数,就能完成以上操作。
其中,栈结构和二叉树结点结构如下:
typedef struct stac
{
stackType* data;
int top;
int Maxsize;
}stack;
void Init_stack(stack* st);//栈初始化
void Clear_stack(stack* st);//清空栈
void Delete_stack(stack* st);
bool IsEmpty_stack(stack* st);
bool IsFull_stack(stack* st);
int Size_stack(stack* st);//求栈大小
stackType Top(stack* st);//获取栈顶
void Pop_stack(stack* st);//出栈
void Push_stack(stack* st, stackType a);//入栈
typedef struct tree{
ElemType data;
struct tree* leftchild;
struct tree* rightchild;
}BinaryTree,*BTree;