【经验杂谈3】头歌-递归与非递归(栈)

1.1递归实现交换二叉树左右子树

void exchange(BiTree T) {
    if (T == NULL) {
        return;
    }

    // 交换当前节点的左右子树
    BiTree temp = T->lchild;
    T->lchild = T->rchild;
    T->rchild = temp;

    // 递归交换左子树和右子树
    exchange(T->lchild);
    exchange(T->rchild);

    // 最后释放节点内存
    free(T);
}

1.2使用栈来实现交换二叉树的左右子树

void exchange(BiTree T)
{
    if (T == NULL) {
        return;
    }

    // 创建一个栈
    Stack s;
    initStack(&s);

    // 将根节点压入栈
    if(T)
    	push(&s, T);

    while (!isEmpty(&s)) {
        // 从栈中弹出一个节点
        BiTree node = pop(&s);

        // 交换该节点的左右子树
        BiTree temp = node->lchild;
        node->lchild = node->rchild;
        node->rchild = temp;

        // 如果该节点有左子树,则将左子树压入栈
        if (node->lchild) {
            push(&s, node->lchild);
        }

        // 如果该节点有右子树,则将右子树压入栈
        if (node->rchild) {
            push(&s, node->rchild);
        }
    }
}

使用栈来进行操作,更容易理解。主要思路是结点进栈->出栈->执行相关操作->进栈左右节点->执行相关操作->出栈 ···开始循环
在这里,相关操作指的是交换本次出栈节点的左右子节点。

2.1使用栈非递归实现先序遍历

void ProOrderTraverse(BiTree T,void(*Visit)(TElemType))
{  // 采用二叉链表存储结构,Visit是对数据元素操作的应用函数。
   // 先序遍历二叉树T的非递归算法,对每个数据元素调用函数Visit
  SqStack s;//定义并初始化栈
  InitStack(s);
  BiTNode * p;
  if(T==NULL)
      return;
  Push(s,T);
  while(!StackEmpty(s))
  {
    Pop(s,p);
    Visit(p->data); 
    if(p->rchild)
        Push(s, p->rchild);
    if(p->lchild)
        Push(s, p->lchild);
  }
  DestroyStack(s);   
}  

实现先序遍历,由于是根->左->右,主要访问当前节点,便于实现,可以使用:结点进栈->出栈->执行相关操作->进栈左右节点->执行相关操作->出栈 ···开始循环
这里的相关操作是 访问当前节点。

2.2使用栈非递归实现中序遍历

由于是中序遍历,左->根->右,对任意一个结,先要访问他的左节点,所以就不能:结点进栈->出栈->执行相关操作->进栈左右节点->执行相关操作->出栈···

// 中序遍历
void inOrderTraversal(struct TreeNode *root) {
    struct StackNode *stack = NULL;
    struct TreeNode *current = root;

    while (current != NULL || !isStackEmpty(stack)) {
        // 遍历左子树
        while (current != NULL) {
            push(&stack, current);
            current = current->left;
        }

        current = pop(&stack);
        printf("%d ", current->val); // 访问节点,可以替换为其他操作
        current = current->right;
    }
}

整个代码段的逻辑是:

尽可能向左走,把每个经过的节点压入栈中。
当无法继续向左走时,从栈中弹出一个节点访问。
访问完弹出的节点后,尝试访问其右子树。
其实当全部左子树压入栈之后,最后的那个叶节点肯定没有左节点,(左已完成)下一步就是针对最小单元的二叉树进行中序遍历。先出栈(根),再入栈右边,再入栈右部分的左子树···

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值