• 剑指offer之树


    //Tree in 剑指offer
    /*
    面试题7:重建二叉树
    输入某二叉树的前序遍历和中序遍历的结果,请重建
    该二叉树。
    */
    typedef struct BinaryTreeNode{
      int m_nValue;
      BinaryTreeNode* m_pLeft;
      BinaryTreeNode* m_pRight;
    }BinaryTreeNode;
    
    BinaryTreeNode* Construct(int *preorder, int *inorder, int length)
    {
      if(preorder == NULL || inorder == NULL || (length <= 0))
         return NULL;
    
      return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1);
    }
    
    BinaryTreeNode* ConstructCore(int *sPreorder, int* ePreorder, int* sInorder, int* eInorder)
    {
      int rootValue = sPreorder[0];
      BinaryTreeNode* root = (BinaryTreeNode*)malloc(sizeof(struct BinaryTreeNode));
      root->m_nValue = rootValue;
      root->m_pLeft = root->m_pRight = NULL;
    
      if(sPreorder = eInorder)
      {
        if(sInorder == eInorder && *sPreorder == *sInorder) return NULL;
        else goto;
      }
    
      //find the address in Inorder array
      int *rootInorder = sInorder;
      while(rootInorder <= eInorder && *rootInorder != rootValue)
        rootInorder++;
      //may the root don't have right subtree
      //找遍整个中序序列都无法找到根节点值 error
      if(rootInorder == eInorder && *rootInorder != rootValue)
         goto;
    
       int leftLength = rootInorder - sInorder;
       int *leftPreorderEnd = sPreorder + leftLength;
    
       //if there is a left subtree
       if(leftLength > 0)
       {
         root->left = ConstructCore(sPreorder+1, leftPreorderEnd, sInorder, rootInorder-1);
       }
       //if there is a right subtree
       if(leftLength < ePreorder - sPreorder)
       {
         root->right = ConstructCore(leftPreorderEnd+1, ePreorder, rootInorder+1, eInorder);
       }
    
       return root;
    }
    
    
    
    /*
    面试题8: 二叉树的下一个节点
    给定一颗二叉树和其中一个节点,如何找出中序遍历序列的
    下一个节点?树中的节点除了有两个分别指向左、右子节点的指针
    还有一个指向父节点的指针
    */
    /*
    1)该节点有右子树 返回右子树最左边的节点
    2)该节点无右子树 但该节点是其父节点的左子树
                   3)但该节点是其父节点的右子树
    */
    BinaryTreeNode* GetNext(BinaryTreeNode* pNode)
    {
      if(pNode == NULL) return NULL;
      if(pNode->right)
      {
        BinaryTreeNode *pRighgt = pNode->right;
        while(pRighgt->left)
        {
          pRighgt = pRighgt->left;
        }
         return pRight;
      }
      else if(pNode->m_nParent)
      {
        BinaryTreeNode *pParent = pNode->m_nParent;
        BinaryTreeNode *pCurrent = pNode;
        while(pParent != NULL && pCurrent != pParent->right)
        {
          pCurrent = pParent;
          pParent = pParent->m_nParent;
        }
    
        return pParent;
      }
    }
    
    
    
    /*
    面试题26:树的子结构
    输入两棵二叉树A和B,判断B是不是A的子结构。二叉树的节点定义如下:
    struct BinaryTreeNode
    {
      double m_dbvalue;
      BinaryTreeNode* m_pLeft;
      BinaryTreeNode* m_pRight;
    };
    */
    bool HasSubtree(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
    {
      bool flag = false;
      if(pRoot1 != NULL && pRoot2 != NULL)
      {
        if(Equal(pRoot1->m_dbvalue,pRoot2->m_dbvalue))
          flag = DoesTree1HaveTree2(pRoot1,pRoot2);
        if(!flag)
          flag = HasSubtree(pRoot1->m_pLeft,pRoot2);
        if(!flag)
          flag = HasSubtree(pRoot1->m_pRight,pRoot2);
      }
      return flag;
    }
    
    
    bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2)
    {
      if(pRoot1 == NULL) return false;
      if(pRoot2 == NULL) return true;
    
      if(!Equal(pRoot1->m_dbvalue,pRoot2->m_dbvalue)) return false;
    
      return DoesTree1HaveTree2(pRoot1->m_pLeft,pRoot2->m_pLeft) && DoesTree1HaveTree2(pRoot1->m_pRight,pRoot2->m_pRight);
    }
    
    
    bool Equal(double num1, double num2)
    {
      if((num1 - num2 > -0.0000001) && (num1 - num2 < 0.0000001))
        return true;
      else
        return false;
    }
    
    
    
    /*
    面试题27:二叉树的镜像
    完成一个函数,输入一棵二叉树,该函数输出它的镜像。二叉树
    节点定义如下:
    struct BinaryTreeNode
    {
      int m_nValue;
      ...
      ...
    };
    */
    
    //writer
    void MirrorRecursively(BinaryTreeNode* pNode)
    {
      if(pNode == NULL)
        return;
      if(pNode->m_pLeft == NULL && pNode->m_pRight == NULL) return;
    
      BinaryTreeNode *pTemp = pNode->m_pLeft;
      pNode->m_pLeft = pNode->m_pRight;
      pNode->m_pRight = pTemp;
    
      if(pNode->m_pLeft) MirrorRecursively(pNode->m_pLeft);
      if(pNode->m_pRight) MirrorRecursively(pNode->m_pRight);
    }
    
    //mine
    //but didn't be tested
    BinaryTreeNode* mine_Mirror(BinaryTreeNode* T)
    {
      if(!T) return T;
    
      BinaryTreeNode *r = mine_Mirror(T->m_pLeft);
      BinaryTreeNode *l = mine_Mirror(T->m_pRight);
    
      T->m_pLeft = r;
      T->m_pRight = l;
    
      return T;
    }
    
    
    
    /*
    面试题28:对称的二叉树
    实现一个函数,判断它是不是对称的
    如果一个二叉树和他的镜像一样,则它是对称的
    */
    bool isSymmetrical(BinaryTreeNode* pRoot)
    {
      return isSymmetrical(pRoot,pRoot);
    }
    
    bool isSymmetrical(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
    {
      if(pRoot1 == NULL && pRoot2 == NULL) return true;
      if(pRoot1 == NULL || pRoot2 == NULL) return false;
    
      if(pRoot1->m_nValue != pRoot2->m_nValue) return false;
      return isSymmetrical(pRoot1->m_pLeft, pRoot2->m_pRight) && isSymmetrical(pRoot1->m_pRight,pRoot2->m_pLeft);
    }
    
    
    
    /*
    面试题32:从上到下打印二叉树
    思路:层次遍历
    */
    
    /*
    扩展一:分行从上到下打印字符串
    eg:
    8
    6 10
    5 7 9 11
    */
    void Print(BinaryTreeNode* pRoot)
    {
      if(pRoot == NULL)
      {
        return;
      }
    
      q = CreateQueue();
      q.push(pRoot);
      int ToBeDeleted = 1;
      int nextlevel = 0;
    
      while(!isEmpty(q))
      {
        BinaryTreeNode *pNode = q.front();
        printf("%d ",pNode->m_nValue);
        
    
        if(pNode->m_pLeft)
        {
          nextlevel++;
          q.push(pNode->m_pLeft);
        }
    
        if(pNode->m_pRight)
        {
          nextlevel++;
          q.push(pNode->m_pRight);
        }
    
        q.pop();
        --ToBeDeleted;
        //当这一层节点都printf以后
        if(ToBeDeleted == 0)
        {
          printf("
    ");
          ToBeDeleted = nextlevel;
          nextlevel = 0;
        }
      }
    }
    
    
    /*
    扩展2:之字形打印二叉树
    eg:(扩展1)
    8
    10 6
    5 7 9 11
    */
    
    
    //mine
    void Print(BinaryTreeNode* pRoot)
    {
      if(pRoot == NULL)
        return;
    
      s1 = CreateStack();  //奇数层所用的栈
      s2 = CreateStack();  //偶数层所用的栈
      int k = 1;           //当前打印的层数
      s1.push(pRoot);
    
      int nextlevel = 0;
      int ToBeDeleted = 1;
    
      while(!isEmpty(s1) || !isEmpty(s2))
      {
        //当前在打印奇数层
        //应当把子节点压入偶数栈
        if(k % 2 == 1)
        {
          BinaryTreeNode *pNode = s1.top();
          printf("%d ",pNode->m_nValue);
    
          if(pNode->left)
          {
            s2.push(pNode->left);
            nextlevel++;
          }
    
          if(pNode->right)
          {
            s2.push(pNode->right);
            nextlevel++;
          }
    
          s1.pop();
          ToBeDeleted--;
          if(ToBeDeleted == 0)
          {
            k++;
            ToBeDeleted = nextlevel;
            nextlevel = 0;
          }
        }
    
        if(k % 2 == 0)
        {
          BinaryTreeNode *pNode = s2.top();
          printf("%d ",pNode->m_nValue);
    
          if(pNode->right)
          {
            s1.push(pNode->right);
            nextlevel++;
          }
    
          if(pNode->left)
          {
            s1.push(pNode->left);
            nextlevel++;
          }
    
          s2.pop();
          ToBeDeleted--;
          if(ToBeDeleted == 0)
          {
            k++;
            ToBeDeleted = nextlevel;
            nextlevel = 0;
          }
        }
      }
    }
    
    
    
    //writer
    void Print(BinaryTreeNode* pRoot)
    {
      if(pRoot == NULL)
        return;
    
      Stack levels[2];
      levels[0] = CreateStack();
      levels[1] = CreateStack();
      int current = 0;
      int next = 1;
    
      levels[current].push(pRoot);
      while(!levels[0].empty() || !levels[1].empty())
      {
        BinaryTreeNode *pNode = levels[current].top();
        levels[current].pop();
    
        printf("%d ",pNode->m_nValue);
    
        if(current == 0)
        {
          if(pNode->m_pLeft)
            levels[next].push(pNode->m_pLeft);
          if(pNode->m_pRight)
            levels[next].push(pNode->m_pRight);
        }
        else
        {
          if(pNode->m_pRight)
            levels[next].push(pNode->m_pRight);
          if(pNode->m_pLeft)
            levels[next].push(pNode->m_pLeft);
        }
    
        if(levels[current].empty())
        {
          printf("
    ");
          current = 1 - current;
          next = 1 - next;
        }
      }
    }
    
    
    
    /*
    面试题33:二叉搜索树的后序遍历
    输入一个整数数组,判断该数组是不是某二叉搜索树的
    后序遍历结果。如果是则返回true,否则返回false。
    假设输入的数组中的任意两个数字都互不相同
    */
    bool VerifySquenceOfBST(int sequence[], int length)
    {
      if(sequence == NULL || length <= 0) return false;
    
      int root = sequence[length-1];
    
      int i=0;
      for(;i<length-1;i++)
      {
        if(sequence[i] > root) break;
      }
    
      int j = i;
      for(;j<length-1;j++)
      {
        if(sequence[j] < root)
          return false;
      }
    
      bool left = true;
      if(i>0) left = VerifySquenceOfBST(sequence,i);
      bool right = true;
      if(length - i - 1 >0) right = VerifySquenceOfBST(sequence+i,length-i-1);
    
      return (left&&right);
    }
    
    
    
    /*
    面试题34:二叉树中和为某一值的路径
    题目:输入一棵二叉树和整数,打印出二叉树中节点值
    的和为输入整数的所有路径。从树的根节点开始往下一直到
    叶节点所经过的节点形成一条路径。
    */
    void FindPath(BinaryTreeNode* pRoot, int expectedSum)
    {
      if(pRoot == NULL) return;
    
      std::vector<int> path;
      int currentSum = 0;
      FindPath(pRoot, expectedSum, path, currentSum);
    }
    
    void FindPath(BinaryTreeNode* pRoot, int expectedSum, std::vector<int>& path, int currentSum)
    {
      currentSum += pRoot->m_nValue;
      path.push_back(pRoot->m_nValue);
    
      bool isLeaf = (pRoot->m_pLeft == NULL && pRoot->m_pRight == NULL);
      if(currentSum == expectedSum && isLeaf)
      {
        printf("a path is found:");
        std::vector<int>::iterator iter = path.begin();
        for(;iter!=path.end();++iter)
          printf("%d	",*iter);
    
        printf("
    ");
      }
    
      if(pRoot->m_pLeft != NULL)
        FindPath(pRoot->m_pLeft,expectedSum,path,currentSum);
      if(pRoot->m_pRight != NULL)
        FindPath(pRoot->m_pRight,expectedSum,path,currentSum);
    
      path.pop_back();
    }
    
    
    
    /*
    面试题36:二叉搜索树和双链表
    */
    BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
    {
      BinaryTreeNode* pLastNodeInList = NULL;
      Convert(pRootOfTree,&pLastNodeInList);
    
      //返回头节点
      BinaryTreeNode* pHeadOfList = pLastNodeInList;
      while(pHeadOfList != NULL && pHeadOfList->m_pLeft != NULL)
         pHeadOfList = pHeadOfList->m_pLeft;
    
      return pHeadOfList;
    }
    
    void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList)
    {
      if(pNode == NULL) return;
      BinaryTreeNode *pCurrent = pNode;
    
      if(pCurrent->m_pLeft != NULL)
        ConvertNode(pCurrent->m_pLeft,pLastNodeInList);
    
      pCurrent->m_pLeft = *pLastNodeInList;
      if(*pLastNodeInList != NULL)
        (*pLastNodeInList)->m_pRight = pCurrent;
    
      *pLastNodeInList = pCurrent;
    
      if(pCurrent->m_pRight != NULL)
        ConvertNode(pCurrent->m_pRight,pLastNodeInList);
    }
    
    
    
    /*
    面试题37:序列化二叉树
    请实现两个函数,分别用来序列化和反序列化二叉树
    */
    void Serialize(BinaryTreeNode* pRoot, ostream& stream)
    {
      if(pRoot == NULL)
      {
        stream<<"%,";
        return;
      }
    
      stream<<pRoot->m_nValue<<',';
      Serialize(pRoot->m_pLeft,stream);
      Serialize(pRoot->m_pRight,stream);
    }
    
    void Deserialize(BinaryTreeNode* pRoot, istream& stream)
    {
      int number;
      if(ReadStream(stream,&number))   //函数ReadStream每次从流中读取一个数字或其他字符
                                       //读到数字返回true,否则返回false
      {
        *pRoot = new BinaryTreeNode();
        (*pRoot)->m_nValue = number;
        (*pRoot)->m_pLeft = NULL;
        (*pRoot)->m_pRight = NULL;
    
        Deserialize(&((*pRoot)->m_pLeft),stream);
        Deserialize(&((*pRoot)->m_pRight),stream);
      }
    }
    
    
    
    /*
    面试题54: 二叉搜索树的第k大节点
    给定一棵二叉搜索树,找出其中第k大的节点
    */
    BinaryTreeNode* KthNode(BinaryTreeNode* pRoot, unsigned int &k)  //注意,此处为k的引用
    {
      if(pRoot == NULL || k<= 0)
        return NULL;
    
      BinaryTreeNode* res = NULL;
      //中序遍历
      if(pRoot->m_pLeft != NULL)
        res = KthNode(pRoot->m_pLeft,k);
      /*************************************///
      if(res == NULL)
      {
        if(k == 1)  //找到了
          return pRoot;
    
        k--;
      }
      /************************************///
      if(res == NULL && pRoot->m_pRight != NULL)
        res = KthNode(pRoot->m_pRight,k);
    
      return res;
    }
    
    
    
    /*
    面试题55:二叉树的深度
    输入一棵二叉树的根节点,求该树的深度
    深度:最长路径的长度
    */
    int TreeDepth(BinaryTreeNode* pRoot)
    {
      if(pRoot == NULL)
        return 0;
    
      int nLeft = TreeDepth(pRoot->m_pLeft);
      int nRight = TreeDepth(pRoot->m_pRight);
    
      return (nLeft > nRight)?(nLeft+1):(nRight+1);
    }
    
    /*
    扩展:平衡二叉树
    输入一棵二叉树的根节点,判断是不是AVL树
    */
    bool isBalanced(BinaryTreeNode* pRoot)
    {
      if(pRoot == NULL) return true;
      
      int left = TreeDepth(pRoot->m_pLeft);
      int right = TreeDepth(pRoot->m_pRight);
      int diff = left - right;
      if(diff > 1 || diff < -1) return false;
    
      return isBalanced(pRoot->m_pLeft) && isBalanced(pRoot->m_pRight);
    }
    
    //better solution
    bool isBalanced(BinaryTreeNode* pRoot, int *pDepth)
    {
      if(pRoot == NULL)
      {
        *pDepth = 0;
        return true;
      }
    
      int left,right;
      if(isBalanced(pRoot->left,&left) && isBalanced(pRoot->right,&right))
      {
        int diff = left - right;
        if(diff <= 1 && diff >= -1)
        {
          *pDepth = 1+(left>right?left:right);
          return true;
        }
      }
    
      return false;
    }
  • 相关阅读:
    input File 提交文件上传 无法传递数据的原因
    谈谈运维该掌握那些技能
    虚拟机vmware 下Centos 系统磁盘扩容
    jenkins针对不同的项目组对用户进行权限分配
    Mac Catalina 手残误删系统文件恢复过程
    自动化持续集成
    zabbix 监控之主动配置模式
    nginx对请求后缀或IP访问限制
    elasticsearch7.2.1 报错 Received fatal alert: handshake_failure
    使用nexus创建npm私服
  • 原文地址:https://www.cnblogs.com/dzy521/p/9623432.html
Copyright © 2020-2023  润新知