小小c#算法题 - 10 - 求树的深度
树型结构是一类重要的非线性数据结构,树是以分支关系定义的层次结构,是n(n>=0)个结点的有限集。关于树的基本概念不再作过多陈述,相信大家都有了解,如有遗忘,可翻书或去其他网页浏览以温习。
树中结点的最大层次数称为树的深度(Depth)或高度。
本文中以二叉树为例来讲述求树的深度的算法。
在算法开始之前,我们要有数据,即一棵树,树又是结点的集合。所以,应该先定义结点的数据结构(结点的基本属性和操作),然后再定义树的数据结构(树的基本属性和操作)。本文的重点不是讲如何去创建树的数据结构,所以一切从简,本文只是简单构造了结点的数据结构,创建一些结点,然后把这些结点按照逻辑关系关联起来,组成一棵树。而并没有专门去构造树的数据结构,如果要构造树的数据结构,应该有添加结点(InsertChild)的方法,求树的深度也应该作为树的一个方法存在。
下面是结点的类的定义:
class Node
{
public int Value
{
get;
set;
} public Node LeftChild
{
get;
set;
} public Node RightChild
{
get;
set;
}
}
接下来我们就可以定义一系列的结点,设置左右孩子结点形成分支结构的一棵树。下面是Main方法中的代码:
static void Main(string[] args)
{
// 创建结点,并通过设置左右孩子组成一棵树
Node root = new Node() { Value = };
Node level21 = new Node() { Value = };
Node level22 = new Node() { Value = };
Node level31 = new Node() { Value = };
Node level32 = new Node() { Value = };
Node level33 = new Node() { Value = };
Node level41 = new Node() { Value = }; root.LeftChild = level21;
root.RightChild = level22;
level21.LeftChild = level31;
level22.LeftChild = level32;
level22.RightChild = level33;
level32.RightChild = level41; // 求树的深度
//int treeDepth = GetTreeDepth(root); //递归求解
int treeDepth = GetTreeDepthByLoop(root); //非递归求解
Console.WriteLine(treeDepth);
Console.ReadKey();
}
通过以上代码,我们构成了如下的一棵树:
可以看出,这棵树的深度是4。下面就来讨论求树的深度的算法。
1.递归求解:
采用递归可以把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。拿上面生成的树来说,如果要求其深度,那么只要取其左子树(以2为根结点的子树)和右子树(以3为根结点的子树)深度的最大值,然后加1即可。由此递归处理下去,直到一棵树只有一个根结点的时候,可知其深度为1,这里是递归的边界条件,这时可以返回上一层的递归。
下面是代码:
private static int GetTreeDepth(Node root)
{
if (root == null)
{
return ;
}
else
{
int leftTreeDepth = GetTreeDepth(root.LeftChild);
int rightTreeDepth = GetTreeDepth(root.RightChild); if (leftTreeDepth >= rightTreeDepth)
{
return leftTreeDepth + ;
}
else
{
return rightTreeDepth + ;
}
}
}
想不通的同学可以拿上面创建好的树来手动地走一遍。
2.直接求解:
直接求解的思想也十分简单,我们可以称之为广度优先遍历。从根结点开始,得到其所有孩子结点,放到一个集合A中,这个集合A中即第二层(根结点为第一层)的所有结点。如果这个集合A不为空,说明其深度至少为2,这时,我们把记录树的深度的变量加1,由初始的1变为2。然后我们遍历这个集合A中的所有结点,即遍历树的第二层的结点,同时把第二层中所有结点的子结点放到另外一个集合B中,这样,另外一个集合B中存放的就是第三层的结点。如果集合B不为空,那么记录深度的变量再加1。这时清空集合A,准备存放下一层的结点,如此循环下去,其间集合A,B交替使用,一个用来存放正在遍历的结点,一个存放下一次要遍历的孩子结点,直到当某一层的结点数为0时,说明已经到树的最底层,可以退出循环了,记录深度的变量此时的值就是树的深度。
代码如下:
// 循环实现,广度优先遍历
private static int GetTreeDepthByLoop(Node root)
{
if (root == null) return ; int depth = ;
List<Node> nodes1 = new List<Node>();
List<Node> nodes2 = new List<Node>();
List<Node> temp; nodes1.Add(root); while (true)
{
foreach (Node n in nodes1)
{
if (n.LeftChild != null)
{
nodes2.Add(n.LeftChild);
} if (n.RightChild != null)
{
nodes2.Add(n.RightChild);
}
} if (nodes2.Count > ) depth++;
else return depth; nodes1.Clear();
temp = nodes1;
nodes1 = nodes2;
nodes2 = temp;
}
}
}
关于main方法中调用上述两种方法的代码,在给出创建树的代码时已经一并给出。
小小c#算法题 - 10 - 求树的深度的更多相关文章
- 小小c#算法题 - 11 - 二叉树的构造及先序遍历、中序遍历、后序遍历
在上一篇文章 小小c#算法题 - 10 - 求树的深度中,用到了树的数据结构,树型结构是一类重要的非线性数据结构,树是以分支关系定义的层次结构,是n(n>=0)个结点的有限集.但在那篇文章中,只 ...
- PAT-1021 Deepest Root (25 分) 并查集判断成环和联通+求树的深度
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on t ...
- LeetCode Maximum Depth of Binary Tree (求树的深度)
题意:给一棵二叉树,求其深度. 思路:递归比较简洁,先求左子树深度,再求右子树深度,比较其结果,返回:max_one+1. /** * Definition for a binary tree nod ...
- 算法题:求一个序列S中所有包含T的子序列(distinct sub sequence)
题: 给定一个序列S以及它的一个子序列T,求S的所有包含T的子序列.例: S = [1, 2, 3, 2, 4] T = [1, 2, 4] 则S的所有包含T的子序列为: [1, 2, 3, 2, 4 ...
- 小小c#算法题 - 12 - Joseph Circle(约瑟夫环)
约瑟夫环是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数(从1开始报数),数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又 ...
- 小小c#算法题 - 9 - 基数排序 (Radix Sort)
基数排序和前几篇博客中写到的排序方法完全不同.前面几种排序方法主要是通过关键字间的比较和移动记录这两种操作来实现排序的,而实现基数排序不需要进行记录项间的比较.而是把关键字按一定规则分布在不同的区域, ...
- 小小c#算法题 - 7 - 堆排序 (Heap Sort)
在讨论堆排序之前,我们先来讨论一下另外一种排序算法——插入排序.插入排序的逻辑相当简单,先遍历一遍数组找到最小值,然后将这个最小值跟第一个元素交换.然后遍历第一个元素之后的n-1个元素,得到这n-1个 ...
- [面试算法题重做]求1+2+...+n
题目:求1+2+…+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字以及条件判断语句(A?B:C). 不能用条件语句,基本上只有考虑递归. 常规解法: 利用构 ...
- FCC JS基础算法题(10):Falsy Bouncer(过滤数组假值)
题目描述: 删除数组中的所有假值.在JavaScript中,假值有false.null.0."".undefined 和 NaN. 使用filter方法,过滤掉生成的 Boolea ...
随机推荐
- ACM学习历程—SNNUOJ1213 加油站问题(动态规划 || 数学)
题目链接:http://219.244.176.199/JudgeOnline/problem.php?id=1213 这是这次微软实习面试的一道题,当时只相出了一个2n的做法,面试官让我优化成n的做 ...
- vbs查看系统开关机时间
如何获取XP系统的开机时间? 下面给出两种代码,保存到扩展名为vbs的文件中.具体哪个请根据自己需求决定. 一:根据系统日志,查看开机时间和关机时间,---- 使用弹出对话框的形式 Set WMI = ...
- HTML(超文本标记语言)
学习地址:https://developer.mozilla.org/zh-CN/docs/Web/Html
- 如何禁用 a 标签的点击事件
a标签是没有disable属性的 ,如果想用disable 禁用a标签的点击事件,也可以实现: 1.a标签要用disable属性,必须和pointer-events属性一起使用, html代码: &l ...
- php 字符串的分割
http://blog.sina.com.cn/s/blog_71ed1b870102uysa.html
- jQuery判断 form表单提交时一些文本框的判断
一: form表单提交时如果表单里有input标签为空那么不提交form表单. <head> <script type="text/javascript"> ...
- PCIe相关的操作命令
1.lspci --显示列举系统目前的pcie设备 43:00.0 Class 0004: Device 104c:b800 (rev 01) //netra设备 设备编号 ...
- Rails的静态资源管理(五)—— 自定义 Asset Pipeline
官方文档:http://guides.ruby-china.org/asset_pipeline.html http://guides.rubyonrails.org/asset_pipeline.h ...
- app中使用微信分享注意事项
1. 在微信公众平台开通一个微信公众号,https://mp.weixin.qq.com 2. 将自己制作好的已签名的app安装到手机上 3. 下载微信开放平台获取应用签名的apk--- gen ...
- EM算法以及推导
EM算法 Jensen不等式 其实Jensen不等式正是我们熟知的convex函数和concave函数性质,对于convex函数,有 \[ \lambda f(x) + (1-\lambda)f(y) ...