美文网首页
剑指offer 26 树的非递归遍历

剑指offer 26 树的非递归遍历

作者: 再凌 | 来源:发表于2020-05-01 12:33 被阅读0次

    输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
    B是A的子结构, 即 A中有出现和B相同的结构和节点值。

    解题思路

    C语言的非递归方法. 可能是测试用例中没有深层次的二叉树(10000个节点的最大深度13), 因此内存使用优势没有展现出来. 深层次反复调用递归肯定是内存爆表的.

    整体思路和树的非递归遍历方法一致, 将符合要求的节点存储起来(本方法使用了Tree链表结构保存节点信息),在下一次的循环中取出检查

    代码

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     struct TreeNode *left;
     *     struct TreeNode *right;
     * };
     */
    struct Tree {
        struct TreeNode *pos;
        struct Tree *next;
    };
    
    //工具函数: 向某个Tree中添加节点
    void addNode(struct Tree *head, struct TreeNode *item)
    {
        struct Tree *temp = (struct Tree*)malloc(sizeof(struct Tree));
        temp->pos = item;
        temp->next = head->next;
        head->next = temp;
    }
    
    //工具函数: 在某个Tree中取得一个TreeNode节点, 并释放Tree中所占空间
    //本函数不检查是否为空!
    struct TreeNode* findNode(struct Tree *head)
    {
        struct Tree *temp =head->next;
        head->next = temp->next;
        struct TreeNode *result = temp->pos;
        free(temp);
        return result;
    }
    
     //工具函数: 在A中找到起始位置, 将所有符合的起始位置都加入startA
     //如果没有找到, 则返回false
    bool findPosition(struct Tree *startA, struct TreeNode *A, int val)
    {
        struct TreeNode *pos = A;
        struct Tree *mark = (struct Tree*)malloc(sizeof(struct Tree));//先序遍历
        mark->next = NULL;
        while(pos)
        {
            while(pos)
            {
                if(pos->val == val)
                    addNode(startA, pos);
                if(pos->right) addNode(mark, pos->right);
                pos = pos->left;
            }
            if(mark->next) pos = findNode(mark);
        }
    
        if(startA->next) 
            return true;
        else
            return false;
    }
    
    
    bool isSubStructure(struct TreeNode* A, struct TreeNode* B){
        if(A == NULL) return false;
        if(B == NULL) return false;
        int result = 1;
        struct Tree *checkA = (struct Tree*)malloc(sizeof(struct Tree));//对于每一个有起始节点的位置, checkA链表保存非递归
        struct Tree *checkB = (struct Tree*)malloc(sizeof(struct Tree));//同上
        struct Tree *startA = (struct Tree*)malloc(sizeof(struct Tree));//保存每一个符合起始值符合要求的节点
        startA->next = NULL;
    
    
        if(!findPosition(startA,A, B->val))//没有找到起始节点
            return false;
    
    
        while(startA->next)//对于每一个符合要求的起始节点开始遍历
        {
            result = 1;
            checkA->next = startA->next;//因为这里直接是将一个Tree节点从startA转移到checkA中, 因此不能使用findNode()(会被释放!)
            startA->next = checkA->next->next;
    
            checkB->next = NULL;    //重新初始化checkB链表
            addNode(checkB, B);
        
            
            while(checkB->next)//一直检查到checkB为空, 如果中途有不符合, 会提前退出并置result = 0
            {
                struct TreeNode *tempB = findNode(checkB);
                struct TreeNode *tempA = findNode(checkA);
    
                bool Ahas = (tempA->left), Bhas = (tempB->left);
                if(!Ahas && Bhas) //如果A无子树, 但是B有子树, 那么不符合. 下同
                {
                    result = 0;
                    break;
                }
                Ahas = (tempA->right), Bhas = (tempB->right);
                if(!Ahas && Bhas)
                {
                    result = 0;
                     break;
                }
    
                //对比AB的左右子树
                if((tempA->left) && (tempB->left))
                {
                    if(tempA->left->val != tempB->left->val)
                    {
                        result = 0;
                        break;
                    }
                    addNode(checkA, tempA->left);//将左右子树加入checkA/B链表,等待下一次循环时检查
                    addNode(checkB, tempB->left);
                }
    
                 //可选择的优化策略: 只加入右子树, 左子树直接通过tempA/B = tempA/B->left并continue循环检查
    
    
                 
                if((tempA->right) && (tempB->right))
                {
                    if(tempA->right->val != tempB ->right->val)
                    {
                        result = 0;
                        break;
                    }
                    addNode(checkA, tempA->right);
                    addNode(checkB, tempB->right);
                }
             }
             if(result) return true;//循环结束时因为result==1, 表明全都匹配
                
        }
        return false;
    }
    

    相关文章

      网友评论

          本文标题:剑指offer 26 树的非递归遍历

          本文链接:https://www.haomeiwen.com/subject/hgafghtx.html