【数据结构】二叉树的建立与遍历

算法设计思路

二叉树的建立采用struct指针建立结点,每个结点内建两个struct指针来指向它的左右孩子,其中建立方法可采用先序,中序、后序。这里仅介绍先序建树,中序建树和后序建树实际上殊途同归。
建树代码如下

typedef struct node
{
     
    char data;
    int visit = 0;
    struct node *l, *r;
} btree, *Btree;

void build(Btree &t)
/**
 * @description: 建树
 * 采用先序建树,先根后左右
 * @param {*Btree &t}
 */
{
     
    char s;
    sc("%c", &s);
    if (isdigit(s))
    {
     
        t = new btree;
        t->data = s;
        build(t->l);
        build(t->r);
    }
    else
        t = NULL;
}

这边先简单叙述一下二叉树的先序、中序、后序遍历的递归方法。首先对于先序遍历,采用根左右的顺序输出,所以每遇到一个结点就先输出它对应的值,再先递归它的左孩子然后递归它的右孩子。
代码如下

void pre_rec(Btree t)
/**
 * @description: 递归先序遍历二叉树
 * @param {*Btree t}
 */
{
     
    if (t != NULL)
    {
     
        pr("%c ", t->data);
        pre_rec(t->l);
        pre_rec(t->r);
    }
}
void in_rec(Btree t)
/**
 * @description: 递归中序遍历二叉树
 * @param {*Btree t}
 */
{
     
    if (t != NULL)
    {
     
        in_rec(t->l);
        pr("%c ", t->data);
        in_rec(t->r);
    }
}
void post_rec(Btree t)
/**
 * @description: 递归后序遍历二叉树
 * @param {*Btree t}
 */
{
     
    if (t != NULL)
    {
     
        post_rec(t->l);
        post_rec(t->r);
        pr("%c ", t->data);
    }
}

先序遍历的非递归方法: 从根结点开始往左孩子方向遍历,每遍历到一个元素就把它对应的值输出,然后将该结点入栈,直至左孩子为空,然后弹出栈顶结点,遍历其右子树,如此往复直至栈空且结点为空。

void pre_transe(Btree ti)
/**
 * @description: 非递归先序遍历二叉树
 * 从根结点开始往左孩子方向遍历,每遍历到一个元素就
 * 把它对应的值输出,然后将该结点入栈,直至左孩子为
 * 空,然后弹出栈顶结点,遍历其右子树,如此往复直至
 * 栈空且结点为空。
 * @param {*Btree ti}
 */
{
     
    stack<Btree> s;
    while (ti != NULL || !s.empty())
    {
     
        while (ti != NULL)
        {
     
            pr("%c ", ti->data);
            s.push(ti);
            ti = ti->l;
        }
        if (!s.empty())
        {
     
            ti = s.top()->r;
            s.pop();
        }
    }
}

非递归中序遍历二叉树 从根结点开始往左孩子方向遍历,然后将该结点入栈,直至左孩子为空,然后弹出栈顶结点并输出该结点对应的元素的值,接着遍历其右子树如此往复直至栈空且结点为空。

void in_transe(Btree ti)
/**
 * @description: 非递归中序遍历二叉树
 * 从根结点开始往左孩子方向遍历,然后将该结点入栈,
 * 直至左孩子为空,然后弹出栈顶结点并输出该结点对
 * 应的元素的值,接着遍历其右子树如此往复直至栈空
 * 且结点为空。
 * @param {*Btree ti}
 */
{
     
    stack<Btree> s;
    while (ti != NULL || !s.empty())
    {
     
        while (ti != NULL)
        {
     
            s.push(ti);
            ti = ti->l;
        }
        if (!s.empty())
        {
     
            ti = s.top();
            s.pop();
            pr("%c ", ti->data);
            ti = ti->r;
        }
    }
}

非递归后序遍历二叉树从根节点开始顺序遍历其左孩子,并将每个顺序遍历到的左孩子入栈同时标记其入栈次数,当左孩子为空 时,弹出栈顶元素,判断栈顶元素入栈次数,若为2则输出栈顶元素对应的值,并将栈顶结点置为空,避免陷入死循环,若为1,则将该节点再次入栈,并自增其入栈次数,然后遍历其右子树,如此往复,直至栈空且结点为空。

void post_transe(Btree ti)
/**
 * @description: 非递归后序遍历二叉树
 * 从根节点开始顺序遍历其左孩子,并将每个顺序遍历
 * 到的左孩子入栈同时标记其入栈次数,当左孩子为空
 * 时,弹出栈顶元素,判断栈顶元素入栈次数,若为2则
 * 输出栈顶元素对应的值,并将栈顶结点置为空,避免
 * 陷入死循环,若为1,则将该节点再次入栈,并自增其
 * 入栈次数,然后遍历其右子树,如此往复,直至栈空
 * 且结点为空。
 * @param {*Btree ti}
 */
{
     
    stack<Btree> s;
    while (ti != NULL || !s.empty())
    {
     
        while (ti != NULL)
        {
     
            ti->visit = 1;
            s.push(ti);
            ti = ti->l;
        }
        if (!s.empty())
        {
     
            ti = s.top();
            s.pop();
            if(ti->visit == 1)
            {
     
                ti->visit++;
                s.push(ti);
                ti = ti->r;
            }
            else
            {
     
                if(ti->visit == 2)
                {
     
                    pr("%c ", ti->data);
                    ti = NULL;
                }
            }
        }
    }
}

层序遍历二叉树将根节点入队后,逐一弹出队首元素输出它对应的值并将队首元素的左右孩子入队,如此往复,直至队空

void level_transe(Btree t)
/**
 * @description: 层序遍历二叉树
 * 将根节点入队后,逐一弹出队首元素输出它对应的值
 * 并将队首元素的左右孩子入队,如此往复,直至队空
 * @param {*Btree t}
 */
{
     
    queue<btree> q;
    if (t != NULL)
    {
     
        q.push(*t);
        btree ti;
        while (!q.empty())
        {
     
            ti = q.front();
            q.pop();
            pr("%c ", ti.data);
            if (ti.l != NULL)
                q.push(*ti.l);
            if (ti.r != NULL)
                q.push(*ti.r);
        }
    }
}

你可能感兴趣的:(数据结构与算法,二叉树,指针,数据结构,队列,stack)