求二叉树中节点的最大距离

合集下载

二叉树知识点总结

二叉树知识点总结

二叉树知识点总结1. 二叉树的性质1.1 二叉树的性质一:二叉树的深度二叉树的深度是指从根节点到叶子节点的最长路径长度。

对于一个空树而言,它的深度为0;对于只有一个根节点的树而言,它的深度为1。

根据定义可知,深度为k的二叉树中,叶子节点的深度值为k。

由此可知,二叉树的深度为所有叶子节点深度的最大值。

1.2 二叉树的性质二:二叉树的高度二叉树的高度是指从根节点到叶子节点的最短路径长度。

对于一个空树而言,它的高度为0;对于只有一个根节点的树而言,它的高度为1。

由此可知,二叉树的高度总是比深度大一。

1.3 二叉树的性质三:二叉树的节点数量对于一个深度为k的二叉树而言,它最多包含2^k - 1个节点。

而对于一个拥有n个节点的二叉树而言,它的深度最多为log2(n+1)。

1.4 二叉树的性质四:满二叉树满二叉树是一种特殊类型的二叉树,它的每个节点要么是叶子节点,要么拥有两个子节点。

满二叉树的性质是:对于深度为k的满二叉树而言,它的节点数量一定是2^k - 1。

1.5 二叉树的性质五:完全二叉树完全二叉树是一种特殊类型的二叉树,它的所有叶子节点都集中在树的最低两层,并且最后一层的叶子节点从左到右依次排列。

对于一个深度为k的完全二叉树而言,它的节点数量一定在2^(k-1)和2^k之间。

2. 二叉树的遍历二叉树的遍历是指按照一定的顺序访问二叉树的所有节点。

二叉树的遍历主要包括前序遍历、中序遍历和后序遍历三种。

2.1 前序遍历(Pre-order traversal)前序遍历的顺序是:根节点 -> 左子树 -> 右子树。

对于一个二叉树而言,前序遍历的结果就是按照“根-左-右”的顺序访问所有节点。

2.2 中序遍历(In-order traversal)中序遍历的顺序是:左子树 -> 根节点 -> 右子树。

对于一个二叉树而言,中序遍历的结果就是按照“左-根-右”的顺序访问所有节点。

2.3 后序遍历(Post-order traversal)后序遍历的顺序是:左子树 -> 右子树 -> 根节点。

计算机数据结构今年考研真题及答案

计算机数据结构今年考研真题及答案

20091.为解决计算机与打印机之间速度不匹配的问题,通常设置一个打印数据缓冲区,主机将要输出的数据依次写入该缓冲区,而打印机则依次从该缓冲区中取出数据。

该缓冲区的逻辑结构应该是A.栈B.队列C.树D.图2.设栈S和队列Q的初始状态均为空,元素abcdefg依次进入栈S。

若每个元素出栈后立即进入队列Q,且7个元素出队的顺序是bdcfeag,则栈S的容量至少是A.1 B.2 C.3 D.43.给定二叉树图所示。

设N代表二叉树的根,L代表根结点的左子树,R代表根结点的右子树。

若遍历后的结点序列为3,1,7,5,6,2,4,则其遍历方式是A.LRN B.NRL C.RLN D.RNL4.下列二叉排序树中,满足平衡二叉树定义的是5.已知一棵完全二叉树的第6层(设根为第1层)有8个叶结点,则完全二叉树的结点个数最多是A.39 B.52 C.111 D.1196.将森林转换为对应的二叉树,若在二叉树中,结点u是结点v的父结点的父结点,则在原来的森林中,u和v可能具有的关系是I.父子关系II.兄弟关系III.u的父结点与v的父结点是兄弟关系A.只有IIB.I和IIC.I和IIID.I、II和III7.下列关于无向连通图特性的叙述中,正确的是I.所有顶点的度之和为偶数II.边数大于顶点个数减1 III.至少有一个顶点的度为1A.只有IB.只有IIC.I和IID.I和III8.下列叙述中,不符合m阶B树定义要求的是A.根节点最多有m棵子树 B.所有叶结点都在同一层上C.各结点内关键字均升序或降序排列 D.叶结点之间通过指针链接9.已知关键序列5,8,12,19,28,20,15,22是小根堆(最小堆),插入关键字3,调整后得到的小根堆是A.3,5,12,8,28,20,15,22,19B.3,5,12,19,20,15,22,8,28C.3,8,12,5,20,15,22,28,19D.3,12,5,8,28,20,15,22,1910.若数据元素序列11,12,13,7,8,9,23,4,5是采用下列排序方法之一得到的第二趟排序后的结果,则该排序算法只能是A.起泡排序 B.插入排序 C.选择排序 D.二路归并排序41.(10分)带权图(权值非负,表示边连接的两顶点间的距离)的最短路径问题是找出从初始顶点到目标顶点之间的一条最短路径。

《编程之美》求二叉树中节点的最大距离

《编程之美》求二叉树中节点的最大距离

《编程之美》求二叉树中节点的最大距离问题定义(动态规划)如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义"距离"为两节点之间边的个数。

写一个程序求一棵二叉树中相距最远的两个节点之间的距离。

书上的解法书中对这个问题的分析是很清楚的,我尝试用自己的方式简短覆述。

计算一个二叉树的最大距离有两个情况:情况A: 路径经过左子树的最深节点,通过根节点,再到右子树的最深节点。

情况B: 路径不穿过根节点,而是左子树或右子树的最大距离路径,取其大者。

只需要计算这两个情况的路径距离,并取其大者,就是该二叉树的最大距离。

我也想不到更好的分析方法。

但接着,原文的实现就不如上面的清楚(源码可从这里下载):1234 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081// 数据结构定义structNODE{NODE* pLeft;// 左子树NODE* pRight;// 右子树intnMaxLeft;// 左子树中的最长距离intnMaxRight;// 右子树中的最长距离charchValue;// 该节点的值};intnMaxLen = 0;// 寻找树中最长的两段距离voidFindMaxLen(NODE* pRoot){// 遍历到叶子节点,返回if(pRoot == NULL){return;}// 如果左子树为空,那么该节点的左边最长距离为0 if(pRoot -> pLeft == NULL){pRoot -> nMaxLeft = 0;}// 如果右子树为空,那么该节点的右边最长距离为0 if(pRoot -> pRight == NULL){pRoot -> nMaxRight = 0;}// 如果左子树不为空,递归寻找左子树最长距离if(pRoot -> pLeft != NULL){FindMaxLen(pRoot -> pLeft);}// 如果右子树不为空,递归寻找右子树最长距离if(pRoot -> pRight != NULL){FindMaxLen(pRoot -> pRight);}// 计算左子树最长节点距离if(pRoot -> pLeft != NULL){intnTempMax = 0;if(pRoot -> pLeft -> nMaxLeft > pRoot -> pLeft -> nMaxRight) {nTempMax = pRoot -> pLeft -> nMaxLeft;}else{nTempMax = pRoot -> pLeft -> nMaxRight;}pRoot -> nMaxLeft = nTempMax + 1;}// 计算右子树最长节点距离if(pRoot -> pRight != NULL){intnTempMax = 0;if(pRoot -> pRight -> nMaxLeft > pRoot -> pRight -> nMaxRight) {nTempMax = pRoot -> pRight -> nMaxLeft;}else{nTempMax = pRoot -> pRight -> nMaxRight;}pRoot -> nMaxRight = nTempMax + 1;}// 更新最长距离if(pRoot -> nMaxLeft + pRoot -> nMaxRight > nMaxLen){nMaxLen = pRoot -> nMaxLeft + pRoot -> nMaxRight;}}这段代码有几个缺点:算法加入了侵入式(intrusive)的资料nMaxLeft, nMaxRight使用了全局变量nMaxLen。

数据结构习题及答案

数据结构习题及答案
3
A.bacde
D.ecbad
22. 设用一维数组 A[n]存储一个栈, 令 A[n]为栈底,用整型变量 T 指示当前栈顶位置, A[T] 为栈顶元素。当从栈中弹出一个元素时,变量 T 的变化为( ) 。 A) T=T+1 C) T 不变 B) T=T-1 D) T=n-1
28. 设 s1=”I am a student”,s2=”a student”,则 Index(s1,s2)的值是
29. 假设有二维数组 A5×6,每个元素用相邻的 4 个字节存储,存储器按字节编址。已知 A 的基地址为 1000, 则数组 A 的最后一个元素 a45 的第一个字节的地址是 储时,元素 a14 的第一个字节的地址是 个字节的地址是 30. 一个非空广义表的表头( A.一定是子表 C.不能是子表 。 ) 。 B.一定是原子 D.可以是原子,也可以是子表 ,tail(L)= 。 ; 按行存
O(1)、线性阶
、平方阶 O(n2)、对数阶
4 以下关于数据结构的基本概念中,叙述正确的是 A) 数据元素是数据不可分割的最小单位。 B) 数据是数据对象的子集。 C) 数据元素之间的关系在计算机中可用顺序映像和非顺序映像两种不同的方法表示。 D) 数据结构在计算机中的表示又称为逻辑结构。 5. 在数据结构中,数据的逻辑结构包括( ) 。 A) 线性结构和非线性结构 B) 逻辑结构和物理结构
《数据结构》习题及答案
2013 年 8 月
1
第一章——第五章 习题
一、 单选或填空题

1. 下列程序段中 S 语句的执行频度为 for(i=0;i<n;i++ ) for(j=0;j<i;j++ ) S; 2. 下列算法的时间复杂度是( for(i=0;i<n;i++ ) c[i]=i; 3. 算法的时间复杂度可表示为 O(logn)和指数阶 O(2n)等。 ) 。

Java 数据结构经典题

Java 数据结构经典题

1.把二元查找树转变成排序的双向链表题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。

要求不能创建任何新的结点,只调整指针的指向。

10/ \6 14/ \ / \4 8 12 16转换成双向链表4=6=8=10=12=14=16。

首先我们定义的二元查找树节点的数据结构如下:struct BSTreeNode{int m_nValue; // value of nodeBSTreeNode *m_pLeft; // left child of nodeBSTreeNode *m_pRight; // right child of node};2.设计包含min函数的栈。

定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。

要求函数min、push以及pop的时间复杂度都是O(1)。

3.求子数组的最大和题目:输入一个整形数组,数组里有正数也有负数。

数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。

求所有子数组的和的最大值。

要求时间复杂度为O(n)。

例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,因此输出为该子数组的和18。

4.在二元树中找出和为某一值的所有路径题目:输入一个整数和一棵二元树。

从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。

打印出和与输入整数相等的所有路径。

例如输入整数22和如下二元树10/ \5 12/ \4 7则打印出两条路径:10, 12和10, 5, 7。

二元树节点的数据结构定义为:struct BinaryTreeNode // a node in the binary tree{int m_nValue; // value of nodeBinaryTreeNode *m_pLeft; // left child of nodeBinaryTreeNode *m_pRight; // right child of node};5.查找最小的k个元素题目:输入n个整数,输出其中最小的k个。

并行计算(陈国良版)课后答案

并行计算(陈国良版)课后答案

第三章 互连网络3.1 对于一颗K 级二叉树(根为0级,叶为k-1级),共有N=2^k —1个节点,当推广至m —元树时(即每个非叶节点有m 个子节点)时,试写出总节点数N 的表达式。

答:推广至M 元树时,k 级M 元树总结点数N 的表达式为:N=1+m^1+m^2+。

.。

+m^(k —1)=(1—m^k)*1/(1-m);3.2二元胖树如图3.46所示,此时所有非根节点均有2个父节点.如果将图中的每个椭圆均视为单个节点,并且成对节点间的多条边视为一条边,则他实际上就是一个二叉树。

试问:如果不管椭圆,只把小方块视为节点,则他从叶到根形成什么样的多级互联网络? 答:8输入的完全混洗三级互联网络.3.3 四元胖树如图3.47所示,试问:每个内节点有几个子节点和几个父节点?你知道那个机器使用了此种形式的胖树?答:每个内节点有4个子节点,2个父节点。

CM —5使用了此类胖树结构.3.4 试构造一个N=64的立方环网络,并将其直径和节点度与N=64的超立方比较之,你的结论是什么?答:A N=64的立方环网络,为4立方环(将4维超立方每个顶点以4面体替代得到),直径d=9,节点度n=4B N=64的超立方网络,为六维超立方(将一个立方体分为8个小立方,以每个小立方作为简单立方体的节点,互联成6维超立方),直径d=6,节点度n=63.5 一个N=2^k 个节点的 de Bruijin 网络如图3。

48。

个节点的二进制表示,。

试问:该网络的直径和对剖宽度是多少?答:N=2^k 个节点的 de Bruijin 网络 直径d=k 对剖宽带w=2^(k-1)3.6 一个N=2^n 个节点的洗牌交换网络如图3.49所示.试问:此网络节点度==?网络直径==?网络对剖宽度==?答:N=2^n 个节点的洗牌交换网络,网络节点度为=2 ,网络直径=n —1 ,网络对剖宽度=43.7 一个N=(k+1)2^k 个节点的蝶形网络如图3.50所示.试问:此网络节点度=?网络直径=?网络对剖宽度=?答:N=(k+1)2^k 个节点的蝶形网络,网络节点度=4 ,网络直径=2*k ,网络对剖宽度=2^k3。

二叉树常见面试题(进阶)

二叉树常见面试题(进阶)

⼆叉树常见⾯试题(进阶)⼀、常见题型1. 求两个节点的最近公共祖先;2. 求⼆叉树中最远的两个节点的距离;3. 由前序遍历和中序遍历重建⼆叉树(如:前序序列:1 2 3 4 5 6 - 中序序列:3 2 4 1 6 5);4. 判断⼀棵树是否是完全⼆叉树;5. 将⼆叉搜索树转换成⼀个排序的双向链表。

要求不能创建任何新的结点,只能调整树中结点指针的指向;6.求⼆叉树的宽度;7. 判断⼀棵⼆叉树是否是平衡⼆叉树;8.判断⼀颗⼆叉树是否是另⼀颗树的⼦树。

⼆、解题思路分析1.两个节点的最近公共祖先求两个节点的最近公共祖先可分为三种情况,分别为:(1)求搜索⼆叉树的最近公共祖先。

根据搜索⼆叉树的性质,左⼦树的所有节点⽐根节点⼩,右⼦树的所有节点⽐跟节点⼤。

如果两个节点都⽐根节点⼩,则递归左⼦树;如果两个节点都⽐跟节点⼤,则递归右⼦树;否则,两个节点⼀个在左⼦树,⼀个在右⼦树,则当前节点就是最近公共祖先节点。

1 Node* GetAncestor(Node* root, Node* x1, Node* x2)//1.该⼆叉树为搜索⼆叉树2 {3 assert(x1 && x2);4if (x1->_data <= root->_data && x2->_data <= root->_data)5 {6return GetAncestor(root->_left, x1, x2);//两个节都⼩于根节点,最近公共祖先在左⼦树中7 }8else if (x1->_data > root->_data && x2->_data > root->_data)9 {10return GetAncestor(root->_right, x1, x2);//两个节都⼤于根节点,最近公共祖先在左⼦树中11 }12else13return root; //⼀个在左⼦树,⼀个在右⼦树,找到公共祖先1415 }(2)三叉链,带⽗节点时求最近公共祖先,⼆叉树节点有指向⽗节点的指针。

九章算法——精选推荐

九章算法——精选推荐

九章算法前⾔第⼀天的算法都还没有缓过来,直接就进⼊了第⼆天的算法学习。

前⼀天⼀直在整理Binary Search的笔记,也没有提前预习⼀下,好在Binary Tree算是⾃⼰最熟的地⽅了吧(LeetCode上⾯Binary Tree的题刷了4遍,⽬前95%以上能够Bug Free)所以还能跟得上,今天听了⼀下,觉得学习到最多的,就是把Traverse和Divide Conquer分开来讨论,觉得开启了⼀⽚新的天地!今天写这个博客我就尽量把两种⽅式都写⼀写吧。

Outline:⼆叉树的遍历前序遍历traverse⽅法前序遍历⾮递归⽅法前序遍历分治法遍历⽅法与分治法Maximum Depth of Binary TreeBalanced Binary Tree⼆叉树的最⼤路径和 (root->leaf)Binary Tree Maximum Path Sum II (root->any)Binary Tree Maximum Path Sum (any->any)⼆叉查找树Validate Binary Search TreeBinary Search Tree Iterator⼆叉树的宽度优先搜索Binary Tree Level-Order Traversal课堂笔记1.⼆叉树的遍历这个应该是⼆叉树⾥⾯最基本的题了,但是在⾯试过程中,不⼀定会考递归的⽅式,很有可能会让你写出⾮递归的⽅法,上课的时候⽼师也提到过,应该直接把⾮递归的⽅法背下来。

这⾥我就不多说了,直接把中序遍历的两种⽅法贴出来吧,最后再加⼊⼀个分治法(这也是第⼀次写,感觉很棒呢,都不需要太多的思考)。

1.1 前序遍历traverse⽅法(Bug Free):vector<int> res;void helper(TreeNode* root) {if (!root) return;res.push_back(root->val);if (root->left) {helper(root->left);}if (root->right) {helper(root->right);}}vector<int> preorderTraversal(TreeNode *root) {if (!root) {return res;}helper(root);return res;}1.2 前序遍历⾮递归⽅法(Bug Free):vector<int> preorderTraversal(TreeNode *root) {vector<int> res;if (!root) {return res;}stack<TreeNode*> s;s.push(root);while (!s.empty()) {TreeNode* tmp = s.top();s.pop();res.push_back(tmp->val);// 这⾥注意:栈是先进后出,所以先push右⼦树if (tmp->right) {s.push(tmp->right);}if (tmp->left) {s.push(tmp->left);}}return res;}1.3 前序遍历分治法(Java实现):vector<int> preorderTraversal(TreeNode *root) {vector<int> res;if (!root) {return res;}//Dividevector<int> left = preorderTraversal(root->left);vector<int> right = preorderTraversal(root->right);//Conquerres.push_back(root->val);res.insert(res.end(), left.begin(), left.end());res.insert(res.end(), right.begin(), right.end());return res;}这三种⽅法也是⽐较直观的,前两个⽐较基础,我就不详细叙述了,但是分治法是值得重点说⼀说的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

求二叉树中节点的最大距离
如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,我们姑且定义“距 离”为两个节点之间边的个数。

写一个程序求一棵二叉树中相距最远的两个节点之间的距离。

如图 3-11 所示,粗箭头的边表示最长距离:
图 3-11
树中相距最远的两个节点 A,B


分析与解法
我们先画几个不同形状的二叉树,(如图 3-12 所示),看看能否得到一些启示。


图 3-12
几个例子 
从例子中可以看出,相距最远的两个节点,一定是两个叶子节点,或者是一个叶子节点 到它的根节点。

(为什么?) 【解法一】 根据相距最远的两个节点一定是叶子节点这个规律,我们可以进一步讨论。

对于任意一个节点,以该节点为根,假设这个根有 K 个孩子节点,那么相距最远的两 个节点 U 和 V 之间的路径与这个根节点的关系有两种情况: 1. 若路径经过根Root,则U和V是属于不同子树的,且它们都是该子树中到根节点最远 的节点,否则跟它们的距离最远相矛盾。

这种情况如图3-13所示:
图 3-13
相距最远的节点在左右最长的子树中


2. 如果路径不经过Root,那么它们一定属于根的K个子树之一。

并且它们也是该子树中 相距最远的两个顶点。

如图3-14中的节点A:
图 3-14
相距最远的节点在某个子树下
因此,问题就可以转化为在子树上的解,从而能够利用动态规划来解决。

设第 K 棵子树中相距最远的两个节点:Uk 和 Vk,其距离定义为 d(Uk, Vk),那么节点 Uk 或 Vk 即为子树 K 到根节点 Rk 距离最长的节点。

不失一般性,我们设 Uk 为子树 K 中到根 节点 Rk 距离最长的节点,其到根节点的距离定义为 d(Uk, R)。

取 d(Ui, R)(1≤i≤k)中 最大的两个值 max1 和 max2,那么经过根节点 R 的最长路径为 max1+max2+2,所以树 R 中 相距最远的两个点的距离为:max{d(U1, V1), …, d(Uk, Vk),max1+max2+2}。

采用深度优先搜索如图 3-15,只需要遍历所有的节点一次,时间复杂度为 O(|E|)= O (|V|-1),其中 V 为点的集合,E 为边的集合。


图 3-15
深度遍历示意图 
示例代码如下,我们使用二叉树来实现该算法。

代码清单 3-11
// 数据结构定义


struct NODE { NODE* pLeft; NODE* pRight; int nMaxLeft; int nMaxRight; char chValue; }; int nMaxLen = 0;
// // // // //
左孩子 右孩子 左子树中的最长距离 右子树中的最长距离 该节点的值
// 寻找树中最长的两段距离 void FindMaxLen(NODE* pRoot) { // 遍历到叶子节点,返回 if(pRoot == NULL) { return; } // 如果左子树为空,那么该节点的左边最长距离为0 if(pRoot -> pLeft == NULL) { pRoot -> nMaxLeft = 0; } // 如果右子树为空,那么该节点的右边最长距离为0 if(pRoot -> pRight == NULL) { pRoot -> nMaxRight = 0; } // 如果左子树不为空,递归寻找左子树最长距离 if(pRoot -> pLeft != NULL) { FindMaxLen(pRoot -> pLeft); } // 如果右子树不为空,递归寻找右子树最长距离 if(pRoot -> pRight != NULL) { FindMaxLen(pRoot -> pRight); } // 计算左子树最长节点距离 if(pRoot -> pLeft != NULL) { int nTempMax = 0; if(pRoot -> pLeft -> nMaxLeft > pRoot -> pLeft -> nMaxRight) { nTempMax = pRoot -> pLeft -> nMaxLeft; } else { nTempMax = pRoot -> pLeft -> nMaxRight; } pRoot -> nMaxLeft = nTempMax + 1; } // 计算右子树最长节点距离 if(pRoot -> pRight != NULL)


{ int nTempMax = 0; if(pRoot -> pRight -> nMaxLeft > pRoot -> pRight -> nMaxRight) { nTempMax = pRoot -> pRight -> nMaxLeft; } else { nTempMax = pRoot -> pRight -> nMaxRight; } pRoot -> nMaxRight = nTempMax + 1; } // 更新最长距离 if(pRoot -> nMaxLeft + pRoot -> nMaxRight > nMaxLen) { nMaxLen = pRoot -> nMaxLeft + pRoot -> nMaxRight; } } 
扩展问题
在代码中, 我们使用了递归的办法来完成问题的求解。

那么是否有非递归的算法来解决 这个问题呢?
总结
对于递归问题的分析,笔者有一些小小的体会: 1. 先弄清楚递归的顺序。

在递归的实现中,往往需要假设后续的调用已经完成,在此 基础之上,才实现递归的逻辑。

在该题中,我们就是假设已经把后面的长度计算出 来了,然后继续考虑后面的逻辑; 2. 分析清楚递归体的逻辑,然后写出来。

比如在上面的问题中,递归体的逻辑就是如 何计算两边最长的距离; 3. 考虑清楚递归退出的边界条件。

也就说,哪些地方应该写return。

注意到以上 3 点,在面对递归问题的时候,我们将总是有章可循。













相关文档
最新文档