剑指offer之树
Posted dzy521
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指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; }
以上是关于剑指offer之树的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode810. 黑板异或游戏/455. 分发饼干/剑指Offer 53 - I. 在排序数组中查找数字 I/53 - II. 0~n-1中缺失的数字/54. 二叉搜索树的第k大节点(代码片段