二叉树非递归算法

程序小白,希望和大家多交流,共同学习

//非递归二叉树借用栈
//使用链栈,
//使用它的原因:1.需要使用先进后出的存储结构;2.需要存储数据个数不定;
//三种遍历存储的虽然都是相同的数据类型,但是使用的目的不一样,所以使用的位置不一样
//先序遍历:根据给定的根节点,直接访问根节点(左结点,有左孩子的结点有两重身份),
//          存储的结点是为了可以很容易的找到右子树的根节点。如此反复。
//中序遍历:根据给定的根节点,在搜索最左结点时,存储所有的根节点。
//          然后使用栈访问根节点,再使用根节点,搜索右子树的根节点。如此反复。
//后续遍历:使用根节点配合栈找到第一个没有左右孩子的结点。栈存储的是每一个结点。
//          为的是,当使用根节点找到第一个没有左孩子的结点后,使用栈找到第一
//          没有右孩子的结点。找到的是第一个既没有左孩子,也没有右孩子的结点。如此反复。
#include<iostream>
using namespace std;
//定义二叉树结点
typedef char elemBTree;
struct BTNode
{
    elemBTree data;//二叉树数据域
    BTNode *lChild, *rChild;//左右孩子
};
typedef BTNode *BTree;

//定义存储二叉树结点的栈
//typedef char elemStack;
typedef BTNode *elemStack;
struct sNode
{
    elemStack data;
    sNode *next;
};
typedef sNode *linkList;
//初始化栈
void initStack(linkList &ls);
//入栈
void push(linkList &ls, elemStack data);
//出栈
void pop(linkList &ls);
//返回栈顶元素
elemStack getTop(linkList ls);
//判空
bool isEmpty(linkList ls);
//判满
bool isFull(linkList ls);

//先序创建二叉树
void preCreateBT(BTree &bt);
//先序遍历二叉树
void preOrder(const BTree &bt);
//中序遍历二叉树
void inOrder(const BTree &bt);
//后续遍历二叉树
void postOrder(const BTree &bt);
//访问结点
void visit(BTNode *node);

int main()
{
    //ABCF##DI##E###G#H##
    BTree bt;
    cout << "先序创建二叉树:";
    preCreateBT(bt);
    cout << "先序遍历二叉树(非递归): ";
    preOrder(bt);
    cout << "\n中序遍历二叉树(非递归): ";
    inOrder(bt);
    cout << "\n后序遍历二叉树(非递归): ";
    postOrder(bt);
    cout << endl;
    return 0;
}

//初始化栈
void initStack(linkList &ls)
{
    ls = NULL;
}
//入栈
void push(linkList &ls, elemStack data)
{
    if (!isFull(ls))
    {
        sNode *newNode = new sNode;
        newNode -> data = data;
        newNode -> next = ls;
        ls = newNode;
    }
    else
        cout << "栈已满,无法入栈";
}
//出栈
void pop(linkList &ls)
{
    if (!isEmpty(ls))
    {
        sNode *delNode = new sNode;
        delNode = ls;
        ls = ls -> next;
        delete delNode;
    }
    else
        cout << "栈空,无法出栈";
}
//返回栈顶元素
elemStack getTop(linkList ls)
{
    return ls -> data;
}
//判空
bool isEmpty(linkList ls)
{
    if (ls == NULL)
    {
        return true;
    }
    else
        return false;
}
//判满
bool isFull(linkList ls)
{
    sNode *newNode = new sNode;
    if (newNode)
    {
        delete newNode;
        return false;
    }
    else
    {
        delete newNode;
        return true;
    }
}

//先序创建二叉树
//对于每个结点,左右孩子为空输入#
void preCreateBT(BTree &bt)
{
    elemBTree elem;
    cin >> elem;
    if (elem == '#')
    {
        bt = NULL;
    }
    else
    {
        bt = new BTNode;//创建新节点
        bt -> data = elem;//为结点数据域赋值
        preCreateBT(bt -> lChild);//以此创建左右孩子
        preCreateBT(bt -> rChild);
    }
}
//先序遍历二叉树
//
void preOrder(const BTree &bt)
{
    BTNode *node = bt;
    linkList ls;
    initStack(ls);

    while (node || !isEmpty(ls))
    {
        while (node)
        {
            visit(node);
            if (node -> rChild)
            {
                push(ls, node);
            }
            node = node -> lChild;
        }

        if (!isEmpty(ls))
        {
            node = getTop(ls);
            pop(ls);
            node = node -> rChild;
        }
    }
}
//中序遍历二叉树
void inOrder(const BTree &bt)
{
    BTNode *node = bt;
    linkList ls;
    initStack(ls);

    while (node || !isEmpty(ls))
    {
        while (node)
        {
            push(ls, node);
            node = node -> lChild;
        }
        if (!isEmpty(ls))
        {
            node = getTop(ls);
            visit(node);
            pop(ls);
            node = node -> rChild;
        }
    }
}
//后续遍历二叉树
//需要亲自模拟才能明白其中pre和node==0的作用
void postOrder(const BTree &bt)
{
    BTNode *node = bt;
    BTNode *pre = NULL;
    linkList ls;
    initStack(ls);

    while (node || !isEmpty(ls))
    {
        while (node)//找最左边的结点(L)
        {
            push(ls, node);
            node = node -> lChild;
        }

        if (!isEmpty(ls))//找第一个没有右孩子的结点(R)
        {
            node = getTop(ls);
            if ((node -> rChild == NULL) || (node -> rChild == pre))
                                            //保证访问完右结点在访问根节点
            {
                visit(node);//(D)
                pop(ls);
                pre = node;//记录最近一次访问的结点,防止重复访问右结点
                node = NULL;//防止重复输入左结点,访问新的左结点,应该在else那里
                            //跳转至新的右子树,然后访问左结点,用while找最左边的结点
            }
            else
                node  = node -> rChild;//当有右孩子的时候,向右转
        }
    }
}
//访问结点
void visit(BTNode *node)
{
    cout << node -> data;
}

猜你喜欢

转载自blog.csdn.net/cheng_cuo_tuo/article/details/80198003