【二叉树】先中后序遍历、二叉链表存储、递归与非递归【转】

思路

先序遍历:若二叉树为空,则空操作;否则访问根节点;先序遍历左子树;先序遍历右子树。

中序遍历:若二叉树为空,则空操作;否则中序遍历左子树;访问根节点;中序遍历右子树。

后序遍历:若二叉树为空,则空操作;否则后序遍历左子树;后序遍历右子树;访问根节点。

二叉链表:链表中的结点包含三个域:数据域和左右指针域。

方法实现

1.二叉树的二叉链表存储表示
typedef char TElemType;
typedef struct BiNode
{
   
    TElemType data;
    struct BiNode *lchild, *rchild;
} BiNode , *BiTree;
2.生成二叉树

先序建立二叉树的二叉链表

/* 
 * 按先序次序输入二叉树中结点的值(一个字符),空格字符表示空树,构造二叉链表表示的二叉树T。
 */
Status CreatBiTree(BiTree *T)
{
   
    char ch;
    scanf("%c", &ch);
 
    //如果当前输入的字符为空格,则(*T)指向空树。
    if (ch == ' ')
    {
   
        (*T) = NULL;
    }
    else
    {
   
        if (!((*T) = (BiTree)malloc(sizeof(BiNode))))
            exit(OVERFLOW);
        (*T)->data = ch;             //生成根结点
        CreatBiTree(&((*T)->lchild));    //构造左子树
        CreatBiTree(&((*T)->rchild));    //构造右子树
    }
    return OK;
}
3.二叉树遍历递归算法
(1)先序遍历
/*
 * 采用二叉链表存储结构,Visit是对数据元素操作的应用函数,
 * 先序遍历二叉树T的递归算法,对每个数据元素调用函数Visit。
 */
Status PreOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
   
    if (T)
    {
   
        if (Visit(T->data))
            if (PreOrderTraverse_Recursive(T->lchild, Visit))
                if (PreOrderTraverse_Recursive(T->rchild, Visit))
                    return OK;
        return ERROR;   //函数不会执行到这一步,不会返回Error。这样写只是为了没有编译警告。
    }
    else
        return OK;  //当T为空树时,停止递归。
}
(2)中序遍历
Status InOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
   
    if (T)
    {
   
        if (InOrderTraverse_Recursive(T->lchild, Visit))
            if (Visit(T->data))
                if (InOrderTraverse_Recursive(T->rchild, Visit))
                    return OK;
        return ERROR;
    }
    else
        return OK;
}
(3)后序遍历
Status PostOrderTraverse_Recursive(BiTree T, Status(*Visit)(TElemType e))
{
   
    if (T)
    {
   
        if (PostOrderTraverse_Recursive(T->lchild, Visit))
            if (PostOrderTraverse_Recursive(T->rchild, Visit))
                if (Visit(T->data))
                    return OK;
        return ERROR;
    }
    else
        return OK;
}
4.二叉树遍历非递归算法
(1)先序遍历
/*
 * 先序遍历二叉树,非递归算法。
 */
Status PreOrderTraverse_NonRecursive(BiTree T, Status(*Visit)(TElemType e))
{
   
    Stack *S;   //栈S中存储指向树结点的指针。
    BiTree p;
    S = (Stack*)malloc(sizeof(Stack));
    InitStack(S);
    Push(S, T); //根指针进栈。
    while (!StackEmpty(S))
    {
   
        //获取栈顶指针,如果栈顶指针不为空,访问该结点。并将该结点的左子树进栈。
        if (GetTop(S, &p) && p)
        {
   
            if (!Visit(p->data))
                return ERROR;
            Push(S, p->lchild);
        }
        //栈顶指针为空,表明之前压入的左子树或者右子树为空。
        else
        {
   
            Pop(S, &p); //空指针退栈
            if (!StackEmpty(S))
            {
   
                Pop(S
### 回答1: 二叉树后序遍历非递归算法可以使用二叉链表作为存储结构来实现。具体实现方法如下: 1. 定义一个栈,用于存储遍历过程中的节点。 2. 从根节点开始,将根节点入栈。 3. 循环执行以下步骤,直到栈为空: a. 取出栈顶节点,如果该节点没有左右子节点或者其左右子节点已经被访问过,则输出该节点的值,并将其出栈。 b. 否则,将该节点的右子节点和左子节点依次入栈。 4. 遍历结束。 需要注意的是,在访问一个节点之前,需要先判断其左右子节点是否已经被访问过,以避免重复访问。另外,由于后序遍历的顺序是左右根,所以在入栈时需要先将右子节点入栈,再将左子节点入栈,以保证出栈顺序的正确性。 ### 回答2: 二叉树后序遍历可以采用非递归算法实现,使用栈作为辅助结构。具体步骤如下: 1.将根节点入栈,如果栈为空则遍历结束,否则执行步骤2。 2.取出栈顶元素,如果该元素为叶子节点或者其左右子树已经遍历完毕,则输出该节点的值,并将其弹出。否则,将该节点再次入栈,先将右子树入栈,再将左子树入栈。这样可以保证左子树会先于右子树被遍历。 3.重复执行步骤2,直到栈为空。 采用二叉链表作为存储结构的二叉树后序遍历非递归算法的实现,需要定义一个栈结构StackNode来辅助遍历。栈中存储的是二叉树的结点指针。 具体实现过程如下: ``` typedef struct StackNode{ BiTNode *p; //指向二叉树结点的指针 int flag; //标记是否访问过 }StackNode; void PostOrder(BiTNode *root) { if(!root) { return; } StackNode stack[MAXSIZE]; //定义一个栈结构 int top = -1; BiTNode *p = root; while(p || top != -1) { while(p) { //先将左子树全部入栈 StackNode node = { p, 0 }; stack[++top] = node; p = p->lchild; } StackNode node = stack[top]; //查看栈顶元素 if(node.flag == 1) { //如果栈顶元素已经访问过 printf("%d ", node.p->data); //输出该结点的值 top--; } else { node.flag = 1; //标记该节点已被访问 stack[top] = node; p = node.p->rchild; //查看该结点的右子树 } } } ``` 这段代码中,先将二叉树的根节点入栈,然后遍历左子树,直到遇到叶子结点。当遇到叶子结点时,从栈中取出该节点,查看是否已经访问过。如果已经访问过,则输出该节点的值,并弹出它;如果没有访问过,则将它的标记位设为1,再将它入栈,查看右子树。如果右子树为空,则弹出该节点。这个算法的时间复杂度为O(n),空间复杂度为O(n)。 ### 回答3: 二叉树是计算机科学中非常重要的数据结构之一,它有多种遍历方式,其中后序遍历是指先访问该结点的左子树,再访问该结点的右子树,最后访问该结点本身。采用二叉链表作为存储结构的二叉树后序遍历非递归算法可以通过栈来实现。 具体实现方法如下: 1. 首先将根节点入栈,并将左子树依次入栈。 2. 当栈顶结点无左子树或者左子树已被访问时,判断是否存在右子树。 3. 如果存在右子树,则将右子树入栈,并重复第一步操作,直到栈为空或所有结点都已被访问。 具体的代码实现如下: ``` struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; vector<int> postorderTraversal(TreeNode* root) { stack<TreeNode*> s; vector<int> result; if (!root) return result; s.push(root); while (!s.empty()) { TreeNode* node = s.top(); if (!node->left && !node->right) { result.push_back(node->val); s.pop(); } else { if (node->right) s.push(node->right); if (node->left) s.push(node->left); node->left = node->right = NULL; } } return result; } ``` 该算法的时间复杂度为 O(n),空间复杂度为 O(log n)(最坏情况下为 O(n))。其中,n 表示树中结点数目。通过采用非递归实现方式,该算法能够有效地避免栈溢出的问题,同时提高遍历效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值