剑指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("\n");
      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("\n");
      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\t",*iter);

    printf("\n");
  }

  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;
}

原文地址:https://www.cnblogs.com/dzy521/p/9623432.html

时间: 2024-07-30 05:37:08

剑指offer之树的相关文章

【剑指offer】树的子结构

转载请注明出处:http://blog.csdn.net/ns_code/article/details/25907685 剑指offer第18题,九度OJ上测试通过! 题目描述: 输入两颗二叉树A,B,判断B是不是A的子结构. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行一个整数n,m(1<=n<=1000,1<=m<=1000):n代表将要输入的二叉树A的节点个数(节点从1开始计数),m代表将要输入的二叉树B的节点个数(节点从1开始计数).

剑指Offer——Trie树(字典树)

剑指Offer--Trie树(字典树) Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种.典型应用是统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优点是:最大限度地减少无谓的字符串比较,查询效率比哈希表高. Trie的核心思想是空间换时间.利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的. Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.可见,优

剑指OFFER之树的子结构(九度OJ1520)

题目描述: 输入两颗二叉树A,B,判断B是不是A的子结构. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行一个整数n,m(1<=n<=1000,1<=m<=1000):n代表将要输入的二叉树A的节点个数(节点从1开始计数),m代表将要输入的二叉树B的节点个数(节点从1开始计数).接下来一行有n个数,每个数代表A树中第i个元素的数值,接下来有n行,第一个数Ki代表第i个节点的子孩子个数,接下来有Ki个树,代表节点i子孩子节点标号.接下来m+1行,与

剑指offer之树的子结构

题目: 树的子结构 链接: https://www.nowcoder.com/practice/6e196c44c7004d15b1610b9afca8bd88?tpId=13&tqId=11170&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 题目描述: 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 思路: 分为两步: 第一步:

[剑指Offer] 17.树的子结构

[思路]要查找树A中是否存在和树B结构一样的子树,可以分成两步: 1.第一步在树A中找到和B的根节点的值一样的结点R:即当前树A包含子树B,HasSubtree(...) 2.第二步再判断树A中以R为根结点的子树是不是包含和树B一样的结构.即当前树A是否是子树B,IsSubtree(...) 1 /* 2 struct TreeNode { 3 int val; 4 struct TreeNode *left; 5 struct TreeNode *right; 6 TreeNode(int x

《剑指offer》-树的子结构

题目描述 输入两颗二叉树A,B,判断B是不是A的子结构. 解法:就是先找到相等的根节点,然后再子树遍历.所以要用到两个递归函数,根节点的递归函数,子树的递归函数. 注意子树的递归函数中应该先判断子树是否遍历完为空,则返回true,每次遍历前都应该判断根节点是否存在.这样就完美了. /* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(N

python剑指offer 实现树的子结构

题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) # -*- coding:utf-8 -*- # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def HasSubtree(self, pRoot1, pRoot2): # write code here if not

剑指Offer 17. 树的子结构 (二叉树)

题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 题目地址 https://www.nowcoder.com/practice/6e196c44c7004d15b1610b9afca8bd88?tpId=13&tqId=11170&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 思路 如果树1或树2为空时,返回False 在树

剑指offer:树的子结构

题目描述输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None class Solution: def HasSubtree(self, pRoot1, pRoot2): def helper(root1, root2): # 如果root2已经遍历完了,说明root2的每一个节点都能在p