zoukankan      html  css  js  c++  java
  • c语言 扎扎实实的线索二叉树的遍历

    看了网上不少线索二叉树的遍历流程代码:拿着严版教材一通copy就直接发到网上,关键的一些代码全都不说明。导致我自己琢磨好久

    现在就把我琢磨的东西发出来分享!

    那我来讲一下我学习的过程中看到这遇到的问题:

    1.如何寻找当前节点的后继

    2.如何确保中序线索遍历一直进行下去

    下面我拿一个例子来进行讲解

    我就拿我这个图来说,我先把他变成线索二叉树形态:

    在编写代码的时候,首先就会思考第一个问题:如何寻找当前节点的下一个后继节点!比如说我要寻找9的后继,比如我要找7的后继节点,再比如我要找1的后继节点

    首先解决第一个小问题:

    寻找9的后继节点很简单:因为变成了线索树,只需要按照紫色箭头所指向的方向走下去即可:

    反应到代码可以这么写:这个地方用到p->rtag就很简单了,只要p这个节点存在直接后继,我就让p走下去

    if(p->rtag==1)
      q
    =p->right;

    第二个小问题:

    如何找到7的后继:我们可以看到图中写到的中序遍历顺序是7到10,那么如何寻找呢?这里就需要总结出一个规律,当一个节点不能靠线索走下去的时候,那么他的后继就是其右孩子的最左边的子树,反应到图中就是7的孙子节点10,也就是9的左子树。

    这里如果我们再变一下,假设10还存在n个左子树,那么7这个节点的后继就是10的最左边的那个孙子节点,反应到代码是这样的

            q=p->right;
            while(q->ltag==0)
                q=q->left;

    代码的意思就是先将当前节点转化为其右节点,然后再沿其右节点一直往左子树的方向走

    但是!注意我这里为什么没有直接写q=q->left;而是写为while条件语句!原因就和第三个小问题有关:

    我们在寻找1这个节点的后继时发现,其右子树为3,当沿着3的左子树走下去的时候,发现3不存在左子树;3

    就是1的直接后继。那么该怎么办呢?

    可不可以将代码改成

    while(q->left!=NULL)
        q=q->left;

    答案是不行。

    看上面我画的线索图,3有一条前驱指针指向1本身,如果按照上面的写法将会形成一个死循环1指向3,3指向1,无法出来。

    所以我们这个地方一定要将while条件判断改成指向当前节点的“左孩子”,左孩子的判断很简单:当前节点的ltag=0的时候一定就有左孩子

    你可能会问:

    若q的左孩子是空怎么办?当前不会为空,之前线索化二叉树的时候已经将所有的空指针线索化了,tag==0就说明指针指向了孩子,tag==1就代表指针指向了前驱或者后继结点,不存在指针为空的情况。

    那么我们的求节点后继的函数就可以这么写

    Node* next(Node *p)
    {
        Node *q=NULL;
        if(p->rtag==1)
            q=p->right;
        else
        {
            q=p->right;
            while(q->ltag==0)
                q=q->left;
        }
        return q;
    }

    写完了如何找到线索二叉树的后继,那么接下来就是如何遍历线索二叉树了:

    我们值到中序二叉树的起点都是最左边的节点开始遍历,那么如何定位到最左边的节点呢?只需要用一个while循环:从根节点开始,不断遍历其左孩子,一直到rtag==1时,就说明不存在左孩子了,进而找到了我们需要的最左边的节点。

            while(p->ltag==0)
            {
                p=p->left;
            }
            printf("%d	",p->data);

    这个地方printf出最左边节点的data,原因是最左边的孩子是中序遍历的第一个节点,自然需要打印出来

    然后就只需要把线索二叉树当成一个链表,不断的往左走就可以了

            while(p->right!=NULL)
            {
                p=next(p);
                printf("%d	",p->data);
            }

     所以整个的代码可以写成这样

    void RunInthread(Node *node)
    {
        if(node==NULL)
            return;
        Node *p=node;
        if(p!=NULL)
        {
            while(p->ltag==0)
            {
                p=p->left;
            }
            printf("%d	",p->data);
            while(p->right!=NULL)
            {
                p=next(p);
                printf("%d	",p->data);
            }
            
        }
    }
  • 相关阅读:
    KMP算法代码实现记录
    冒泡,插入,希尔,快速,归并,桶排序,堆排序算法汇总实现
    回溯法个人理解记录(C#八皇后)
    C#创建初始化链表的方式(个人目前写出3种创建的方式)
    算法汇总代表性学习记录
    C#集合去重
    C#获取数组/字符串的k个字符的全部组合
    pl/sql简单执行记录个人学习记录
    oracle为什么尽量不要使用外键的最好理解
    PickerController 添加照片---iOS
  • 原文地址:https://www.cnblogs.com/oldfish123/p/12995718.html
Copyright © 2011-2022 走看看