二叉树问题汇总(2)—常见问题
2012-07-19 21:43
288 查看
在上一篇二叉树问题汇总(1)中总结了下二叉树的一些基本问题,主要是针对二叉排序树。这篇文章主要汇总二叉树的一些常见的但是难度稍大一点的问题。
比如二叉树如下所示,给定的和为27:
则二叉树存在的根结点到叶结点的路径有:
path 1: 5 4 11 7
path 2: 5 4 11 2
path 3: 5 8 13
path 4: 5 8 4 1
则该二叉树存在和为27的路径,因为5+4+11+7 = 27.若是给定和为40,则不存在这样的路径。
递归主要要理解函数的意义,mirror函数的意义就是得到该二叉树的镜像,二叉树镜像时根结点不变。则mirror(node->left)将左子树镜像,mirror(node->right)将右子树镜像,此时,左右子树的根结点即node->left和node->right还没有交换,所以接下来交换它们,这样就完成了整棵树的镜像过程。
例如原来的二叉搜索树为:
2
/ \
1 3
复制后变成:
如下面(1)(2)两棵二叉树结构相同,但是(1)(3), (2)(3)不相同。
2 2 2
/ \ / \ / \
1 3 1 3 3 1
(1) (2) (3)
特殊情况处理:如果两棵树都为NULL,则相同。其他一棵为NULL,一棵不为NULL则不同。
比如结点数目为3时,结点的data依次为1,2,3,则能够构造5棵二叉搜索树:
1 1 2 3 3
\ \ / \ / /
2 3 1 3 1 2
\ / \ /
3 2 2 1
1、判定二叉树是否存在和为给定值的路径
问题:
给定一个值,判定二叉树是否存在从根结点到叶结点的路径,其结点的数据之和为该值。比如二叉树如下所示,给定的和为27:
则二叉树存在的根结点到叶结点的路径有:
path 1: 5 4 11 7
path 2: 5 4 11 2
path 3: 5 8 13
path 4: 5 8 4 1
则该二叉树存在和为27的路径,因为5+4+11+7 = 27.若是给定和为40,则不存在这样的路径。
解答:
主要思路还是递归,通过用和值减去根结点的值,然后判断左右子树是否存在和为sum-root.data的路径。代码如下:int hasPathSum(struct node* root, int sum) { if (root == NULL) return sum == 0; //基本条件:根结点为NULL,则判断此时剩下的和值是否为0,为0则表示存在,否则不存在 return hasPathSum(root->left, sum-root->data) || hasPathSum(root->right, sum-root->data); //递归判断左右子树 }
2、打印二叉树的所有路径(从根结点到叶结点)
问题:
如1中所示,打印二叉树的所有从根结点到叶结点的路径,如上例中打印输出4条路径。解答:
//打印路径主函数 void printPaths(struct node* root) { int path[1000]; printPathsRecur(root, path, 0); } //递归调用打印路径 void printPathsRecur(struct node* root, int path[], int pathLen) { if (root == NULL) return; path[pathLen++] = root->data; //将根结点加入到路径数组中,路径长度加1 if (root->left==NULL && root->right==NULL) //到了叶子节点,所以打印输出路径。 printArray(path, pathLen); else { printPathsRecur(root->left, path, pathLen); //递归打印左子树 printPathsRecur(root->right, path, pathLen); //递归打印右子树 } } //该函数打印输出路径。路径存储在数组path中,pathLen为路径结点个数。 void printArray(int path[], int pathLen) { int i; for (i=0; i<pathLen; i++) { printf("%d ", path[i]); } printf("\n"); }
3、二叉树镜像
问题:
二叉树镜像问题即是将二叉树所有结点的左右孩子结点指针互换。如下图所示,左边的二叉树的镜像为右边所示。解答:
还是递归。从底向上,先交换完根结点的左右子树,再交换根结点的左右孩子结点。自顶向下也是可以的,即先交换根结点的左右孩子,再递归交换左右子树。递归主要要理解函数的意义,mirror函数的意义就是得到该二叉树的镜像,二叉树镜像时根结点不变。则mirror(node->left)将左子树镜像,mirror(node->right)将右子树镜像,此时,左右子树的根结点即node->left和node->right还没有交换,所以接下来交换它们,这样就完成了整棵树的镜像过程。
//自底向上,即先交换左右子树,再交换左右孩子节点。 void mirror(struct node* node) { if (node==NULL) { return; } else { struct node* temp; // 子树完成镜像 mirror(node->left); mirror(node->right); // 交换node的左右孩子节点 temp = node->left; node->left = node->right; node->right = temp; } }
//自顶向下完成镜像 void mirror2(struct node* root) { if (root == NULL) return; struct node* tmp = root->left; root->left = root->right; root->right = tmp; mirror2(root->left); mirror2(root->right); }
4、二叉搜索树复制
问题:
复制二叉搜索树的各个结点,并插入其中,使得新的二叉树还是一棵二叉搜索树。例如原来的二叉搜索树为:
2
/ \
1 3
复制后变成:
解答:
复制源结点,然后将其作为左孩子插入到源结点中。先复制完左右子树,然后将本结点复制插入到源结点的左孩子中。void doubleTree(struct node* root) { struct node* oldLeft; if (root == NULL) return; doubleTree(root->left); //复制左子树 doubleTree(root->right); //复制右子树 oldLeft = root->left; root->left = newNode(root->data); //复制根结点并将其作为新的左孩子,如图中所示,结点2复制一个作为原来根结点2的左孩子。 root->left->left = oldLeft; //复制的根结点的左孩子为原来的根结点的左孩子。如图中所示,复制的结点2的左孩子为原来根结点的左孩子结点1. }
5、判定两棵二叉树结构是否相同
问题:
给定两棵二叉树,判定其结构是否相同,即对应的所有结点值是否一样。如下面(1)(2)两棵二叉树结构相同,但是(1)(3), (2)(3)不相同。
2 2 2
/ \ / \ / \
1 3 1 3 3 1
(1) (2) (3)
解答:
先判定根结点的data域是否相同,如果相同则继续判断左右子树。一定是根结点和左右子树都相同才能判定两棵二叉树结构相同。特殊情况处理:如果两棵树都为NULL,则相同。其他一棵为NULL,一棵不为NULL则不同。
int sameTree(struct node* a, struct node* b) { if (a==NULL && b==NULL) //两棵树都为空,返回true return true; else if (a!=NULL && b!=NULL) { //两棵树都不为空,则比较根结点和递归比较左右子树 return a->data==b->data && sameTree(a->left, b->left) && sameTree(a->right, b->right); } else //其他情况,一棵树为空,一棵不为空,返回false return false; }
6、二叉搜索树的数目
问题:
给定结点数目num,结点的data值为1,2,3...num。给出这些结点能够构造的二叉搜索树数目。比如结点数目为3时,结点的data依次为1,2,3,则能够构造5棵二叉搜索树:
1 1 2 3 3
\ \ / \ / /
2 3 1 3 1 2
\ / \ /
3 2 2 1
解答:
考虑到每个结点都可能是根结点root,递归计算左右子树,总的数目就是左右子树数目的乘积之和。当结点数目为3时,则当root为1时,则左子树结点为0,只有右子树结点数目为2。当root为2时,则左右子树结点数目为1,1。root为3时,左右子树结点数目为2,0。int countTrees(int numKeys) { if (numKeys <=1) { return(1); } else { int sum = 0; int left, right, root; for (root=1; root<=numKeys; root++) { left = countTrees(root - 1); right = countTrees(numKeys - root); // left*right为当前root的二叉搜索树数目 sum += left*right; } return(sum); }
相关文章推荐
- 重温数据结构:二叉树的常见问题汇总
- linux启动常见问题汇总
- Docker 常见问题汇总
- H5项目常见问题汇总及解决方案
- 云计算 常见问题案例汇总情况
- Android WebView常见问题及解决方案汇总
- 【精细版】知更鸟begin主题使用常见问题汇总
- 使用C++.NET常见问题汇总
- 常见的数据库问题汇总(补充中)
- Installshield脚本拷贝文件常见问题汇总
- IAD开发常见问题汇总(翻译)
- java常见问题解决办法汇总
- Windows Phone 7 开发常见问题汇总
- ab常见问题汇总
- h5开发中常见的问题汇总
- Android项目中嵌入RN常见问题汇总
- 英文面试常见问题汇总
- 深入理解Spring Redis的使用 (五)、常见问题汇总
- Integration Services包部署常见问题汇总 2
- Web前端常见问题汇总