《算法问题实战策略》-chaper21-树的实现和遍历

这一章节开始介绍一个数据结构中的一个基本概念——树。

我们从数据结构的解读来解释树结构的重要性,现实世界的数据除了最基本的线性结构(我们常用队列、数组和链表等结构表征),还有一个重要的特性——层级结构需要我们去表征,例如世界杯的对阵表、遗传系谱图等等,这时候我们基于对现实世界的抽象,会很自然的理解为什么会有树这样一个数据结构。

而树这种数据结构也是能够分类的,我们将每个节点记录某种抽象的概念或者具象的事物,这样用来表征一种从属关系,我们称其为抽象型数据结构的树。或者将每个节点储存一些数据,基于这棵树我们能够完成检索查找之类的操作,我们称其为检索型数据结构的树。

关于树的基本的术语和其中的基本概念,这里不再累述,读者可以通过查找离散数学或者图论的资料了解。

树的实现:

既然了解到了树存在的必要性和重要性,下面我们就应该去关注怎样实现一棵树了。在《啊哈算法》中,作者介绍了用一维数组实现的二叉树,这是基于二叉树一些非常特殊的形式,但是对于更加一般的情况的多叉树呢?我们需要采用更加一般的方法。对于树中的每一个节点,我们很关注如下集合很有价值的数据:它的父节点?它的子节点?存在该节点的数据?关于它的父节点和子节点,其实就是需要我们表征一种“联系”,即通过该节点,我们能够轻松的找到和它关联的父节点和子节点,我们很容易便可以想到指针。而基于一维数组实现的二叉树,就是二叉树的基本性质,通过为节点标号从而实现了指针的作用。

通过上面的分析,我们能够定义树节点的结构体。

struct Treenode

{

    <data>

    TreeNode* parent;

    vector<TreeNode*> children;

};

树的遍历:

树本质上也是一种图,因此这里采用基本的深搜就可以完成对树的遍历。

void printLabels(TreeNode* root)

{

    cout<< root-> <data><<endl;

    for(int i = 0;i < root->chilren.size();i++)

          printLabels(root->children[i]);

}

基于对树的遍历,我们同时可以完成对树的高度的计算。

int height(TreeNode* root)

{

    int h = 0;

    for(int i = 0;i < root->children.size();i++)

          h = max(h,1+height(root->children[i]));

    return h;

}
时间: 2024-08-10 19:07:43

《算法问题实战策略》-chaper21-树的实现和遍历的相关文章

《算法问题实战策略》-chaper7-穷举法

关于这一章节<算法实战策略>有一段概述问题,我认为对于编程人员来说非常有价值,故在这里进行如下的摘抄: 构想算法是很艰难的工作.相比大家都经历过,面对复杂的要求只是傻乎乎地盯着显示器,或者不经过深思熟虑就开始打键盘,结果还要辛辛苦苦修改变得一塌糊涂的代码.经过这些磨难,各位就能切身体会到设计算法的重要性. 与通常所想不同,支配设计算法的并不是一时的灵感,而是许多策略性的选择.构想算法不仅需要理解问题的特性,还要理解执行时间和占用内存空间之间的对立关系,而且要会选择适当的数据结构. 算法设计范式

《算法问题实战策略》-chaper32-网络流

基本的网络流模型: 在图论这一块初步的应用领域中,两个最常见的关注点,其一时图中的路径长度,也就是我们常说的的最短路径问题,另一个则是所谓的“流问题”. 流问题的基本概念: 首先给出一张图. 其实所谓“网络流”,其模型是非常有现实意义的.我们将该图视为计算机网络结构.此图中,s称其为源点而t称其为汇点.这个图中剩余的源泉代表网络设备,连接个顶点的边线表示连接两个设备的数据线缆,边的权值表示这条线缆能够传输的最大数据. 首先我们应该能够注意到,有向路径<s,t>就是一条传输路线,而这条传输数据的

《算法问题实战策略》-chaper13-数值分析

这一章节主要介绍我们在进行数值分析常用的二分.三分策略. 首先介绍二分. 其实二分的思想很好理解并且笔者在之前的一些文章中也有所渗透,对于二次函数甚至单元高次函数的零点求解.线段树还有<algorithm puzzle>当中的“切割钢条”问题,都是基于二分思想. 下面我们通过具体的问题来应用二分这种数值分析的策略. Ex1:按揭贷款 以P%的年利率借贷N元后,在M个月内,以每月还C元的方式还贷.贷款期限内,按照如下形式计算贷款余额. (1)    贷款余额从余额N元开始. (2)    美国一

算法问题实战策略 MEETINGROOm

地址 解答 todo 错误代码 1 // Tarjan_Scc.cpp : 此文件包含 "main" 函数.程序执行将在此处开始并结束. 2 // 3 4 #include "pch.h" 5 6 7 #include <algorithm> 8 #include <iostream> 9 #include <vector> 10 #include <stack> 11 12 using namespace std;

《算法问题实战策略》——chaper9——动态规划法技巧

Q1: 数字游戏: 两个人(A.B)用n个整数排成的一排棋盘玩游戏,游戏从A开始,每个人有如下操作: (1)    拿走棋盘最右侧或者最左侧的棋子,被拿走的数字从棋盘中抹掉. (2)    棋盘中还剩下两个以上的数字的时候,可以把棋盘最右侧或者最左侧的两个数字抹掉 当棋盘上的所有数字消失之后,游戏结束,谁拿的棋子代表的整数之和较大谁赢,现在假设两个游戏者都是聪明的,给出长度为n的序列,请计算游戏结束之后A的分数和B的分数的差值. 分析:其实相似的问题在<训练指南>当中曾经分析过,那个题目叫做“

《算法问题实战策略》-chaper14-整数论

Lucas定理: 在组合计数问题中,我们常面临组合数C(n,m)过大而无法直接计算的困境,那么这里的Lucas定理给出了一个较大组合数进行取余运算的一种递归算法. 什么是Lucas定理? Lucas定理的推导证明? 这个推导过程基于二项式定理,基于最后的等式,我们通过过找等是左边和右边x^(tp + r)的系数,即可完成对Lucas定理的证明.但是这里并没有呈现对p为什么是素数的说明. 在这里我们给出Lucas定理的另外一种表达形式: 我个人认为,限定了取模的数p是素数,这样统一了运算,即对于∏

算法问题实战策略 QUADTREE

地址 https://algospot.com/judge/problem/read/QUADTREE 将压缩字符串还原后翻转再次压缩的朴素做法 在数据量庞大的情况下是不可取的 所以需要在压缩的情况下进行翻转 图片可以分成四块 每块在颜色不统一的情况下又会分成四块 那么翻转也可以采取这种逐步将问题分解成小块翻转 然后再处理大块算法 最后的到结果的算法 代码如下 #include <iostream> #include <string> using namespace std; /*

算法问题实战策略 DICTIONARY

地址 https://algospot.com/judge/problem/read/DICTIONARY 解法 构造一个26字母的有向图 判断无回路后 就可以输出判断出来的字符序了 比较各个字母的先后次序不必用一个单词分别同其他单词比较 只需要将临近的两个单词一一比较即可 证明如下 算法1 中判断有无回路 采取的是DFS方法 代码 1 #include <iostream> 2 #include <string> 3 #include <vector> 4 #incl

算法问题实战策略 GALLERY

地址 https://algospot.com/judge/problem/read/GALLERY 分析 如图 显然是需要在 0 1 2三个点进行监控即可.(0 2 3 也可) 根据题意,不存在回路,也就是不重复经过两画廊之间的走廊是不可能在两画廊之间进行走动的 我们可以将该图看成一棵树,深度优先遍历时,叶子结点的父节点需要放置摄像头,这样能将叶子结点 父节点和父节点的父节点均可监视到.然后根据有无未监视的子节点 决定当前节点的状态(需要放置,被监视,未被监视) 代码如下 1 #include