数据结构丨N叉树
遍历
N叉树的遍历
树的遍历
一棵二叉树可以按照前序、中序、后序或者层序来进行遍历。在这些遍历方法中,前序遍历、后序遍历和层序遍历同样可以运用到N叉树中。
回顾 - 二叉树的遍历
- 前序遍历 - 首先访问根节点,然后遍历左子树,最后遍历右子树;
- 中序遍历 - 首先遍历左子树,然后访问根节点,最后遍历右子树;
- 后序遍历 - 首先遍历左子树,然后遍历右子树,最后访问根节点;
- 层序遍历 - 按照从左到右的顺序,逐层遍历各个节点。
请注意,N叉树的中序遍历没有标准定义,中序遍历只有在二叉树中有明确的定义。尽管我们可以通过几种不同的方法来定义N叉树的中序遍历,但是这些描述都不是特别贴切,并且在实践中也不常用到,所以我们暂且跳过N叉树中序遍历的部分。
把上述关于二叉树遍历转换为N叉树遍历,我们只需把如下表述:
遍历左子树... 遍历右子树...
变为:
对于每个子节点:
通过递归地调用遍历函数来遍历以该子节点为根的子树
我们假设for循环将会按照各个节点在数据结构中的顺序进行遍历:通常按照从左到右的顺序,如下所示。
N叉树遍历示例
我们用如图所示的三叉树来举例说明:
1.前序遍历
在N叉树中,前序遍历指先访问根节点,然后逐个遍历以其子节点为根的子树。
例如,上述三叉树的前序遍历是: A->B->C->E->F->D->G.
2.后序遍历
在N叉树中,后序遍历指前先逐个遍历以根节点的子节点为根的子树,最后访问根节点。
例如,上述三叉树的后序遍历是: B->E->F->C->G->D->A.
3.层序遍历
N叉树的层序遍历与二叉树的一致。通常,当我们在树中进行广度优先搜索时,我们将按层序的顺序进行遍历。
例如,上述三叉树的层序遍历是: A->B->C->D->E->F->G.
练习
接下来,我们将为你提供几道与N叉树相关的习题。
N-ary Tree Preorder Traversal
给定一个 N 叉树,返回其节点值的前序遍历。
例如,给定一个 3叉树
:
返回其前序遍历: [1,3,5,6,2,4]
。
说明: 递归法很简单,你可以使用迭代法完成此题吗?
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
class Node{
public:
int val;
vector<Node*> children;
Node(){}
Node(int _val, vector<Node*>_children){
val = _val;
children = _children;
}
};
/// Recursion
/// Time Complexity: O(n)
/// Space Complexity: O(h)
class SolutionA{
public:
vector<int> preorder(Node* root){
vector<int> res;
dfs(root, res);
return res;
}
private:
void dfs(Node* node, vector<int>& res){
if(!node)
return;
res.push_back(node->val);
for(Node* next: node->children)
dfs(next, res);
}
};
/// Non-Recursion
/// Using stack
/// Time Complexity: O(n)
/// Space Complexity: O(h)
class SolutionB{
public:
vector<int> preorder(Node* root){
vector<int> res;
if(!root)
return res;
stack<Node*> stack;
stack.push(root);
while(!stack.empty()){
Node* cur = stack.top();
stack.pop();
res.push_back(cur->val);
for(vector<Node*>::reverse_iterator iter = cur->children.rbegin();
iter != cur->children.rend(); iter++)
stack.push(*iter);
}
return res;
}
};
int main(){
return 0;
}
N-ary Tree Postorder Traversal
给定一个 N 叉树,返回其节点值的后序遍历。
例如,给定一个 3叉树
:
返回其后序遍历: [5,6,3,2,4,1]
.
说明: 递归法很简单,你可以使用迭代法完成此题吗?
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
class Node{
public:
int val;
vector<Node*> children;
Node(){}
Node(int _val, vector<Node*> _children){
val = _val;
children = _children;
}
};
/// Recursion
/// Time Complexity: O(n)
/// Space Complexity: O(h)
class SolutionA{
public:
vector<int> postorder(Node* root){
vector<int> res;
dfs(root, res);
return res;
}
private:
void dfs(Node* node, vector<int>& res){
if(!node)
return;
for(Node* next: node->children)
dfs(next, res);
res.push_back(node->val);
}
};
/// Non-Recursion
/// Using stack
///
/// Time Complexity: O(n)
/// Space Complexity: O(h)
class SolutionB{
public:
vector<int> postorder(Node* root){
vector<int> res;
if(!root)
return res;
stack<Node*> stack;
stack.push(root);
while(!stack.empty()){
Node* cur = stack.top();
stack.pop();
res.push_back(cur->val);
for(Node* next: cur->children)
stack.push(next);
}
reverse(res.begin(), res.end());
return res;
}
};
int main(){
return 0;
}
N叉树的层序遍历
给定一个 N 叉树,返回其节点值的层序遍历。 (即从左到右,逐层遍历)。
例如,给定一个 3叉树
:
返回其层序遍历:
[
[1],
[3,2,4],
[5,6]
]
说明:
- 树的深度不会超过
1000
。 - 树的节点总数不会超过
5000
。
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
class Node {
public:
int val = NULL;
vector<Node*> children;
Node() {}
Node(int _val, vector<Node*> _children) {
val = _val;
children = _children;
}
};
/// BFS
/// Store step in the queue
///
/// Time Complexity: O(n)
/// Space Complexity: O(n)
class SolutionA{
public:
vector<vector<int>> levelOrder(Node* root){
vector<vector<int>> res;
if(!root)
return res;
queue<pair<Node*, int>> q;
q.push(make_pair(root, 0));
while(!q.empty()){
Node* cur = q.front().first;
int step = q.front().second;
q.pop();
if(step == res.size())
res.push_back({cur->val});
else
res[step].push_back(cur->val);
for(Node* next: cur->children)
q.push(make_pair(next, step + 1));
}
return res;
}
};
int main(){
return 0;
}
递归
N叉树的经典递归解法
经典递归法
我们在之前的章节中讲过如何运用递归法解决二叉树问题。在这篇文章中,我们着重介绍如何将这个思想引入到N叉树中。
在阅读以下内容之前,请确保你已阅读过 运用递归解决树的问题 这篇文章。
- "自顶向下"的解决方案
"自顶向下"意味着在每个递归层次上,我们首先访问节点以获得一些值,然后在调用递归函数时,将这些值传给其子节点。
一个典型的 "自顶向下" 函数 top_down(root, params)
的工作原理如下:
1. 对于 null 节点返回一个特定值
2. 如果有需要,对当前答案 answer 进行更新 // answer <-- params
3. for each child node root.children[k]:
4. ans[k] = top_down(root.children[k], new_params[k]) // new_params <-- root.val, params
5. 如果有需要,返回答案 answer // answer <-- all ans[k]
- "自底向上"的解决方案
"自底向上" 意味着在每个递归层次上,我们首先为每个子节点递归地调用函数,然后根据返回值和根节点本身的值给出相应结果。
一个典型的 "自底向上" 函数 bottom_up(root)
的工作原理如下:
1.对于 null 节点返回一个特定值
2.for each child node root.children[k]:
3. ans[k] = bottom_up(root.children[k]) // 为每个子节点递归地调用函数
4. 返回答案 answer // answer <- root.val, all ans[k]
Maximum Depth of N-ary Tree
给定一个 N 叉树,找到其最大深度。
最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
例如,给定一个 3叉树
:
我们应返回其最大深度,3。
说明:
- 树的深度不会超过
1000
。 - 树的节点总不会超过
5000
。
#include <iostream>
#include <vector>
using namespace std;
/// DFS
/// Time Complexity: O(n)
/// Space Complexity: O(n)
/// Definition for a Node.
class Node{
public:
int val;
vector<Node*> children;
Node(){}
Node(int _val, vector<Node*> _children){
val = _val;
children = _children;
}
};
class Solution{
public:
int maxDepth(Node* root){
if(!root)
return 0;
int res = 1;
for(Node* child: root->children)
res = max(res, 1 + maxDepth(child));
return res;
}
};
int main(){
return 0;
}
小结
这张卡旨在介绍N叉树
的基本思想。 实际上,二叉树
只是N叉树
的一种特殊形式,N叉树
相关问题的解决方案与二叉树
的解法十分相似。 因此,我们可以把在二叉树
中学到的知识扩展到N叉树中。
我们提供了一些经典的N叉树
习题,以便进一步帮助你理解本章中N叉树
的概念。
数据结构丨N叉树的更多相关文章
- C#数据结构-线索化二叉树
为什么线索化二叉树? 对于二叉树的遍历,我们知道每个节点的前驱与后继,但是这是建立在遍历的基础上,否则我们只知道后续的左右子树.现在我们充分利用二叉树左右子树的空节点,分别指向当前节点的前驱.后继,便 ...
- js:数据结构笔记9--二叉树
树:以分层的方式存储数据:节点:根节点,子节点,父节点,叶子节点(没有任何子节点的节点):层:根节点开始0层: 二叉树:每个节点子节点不超过两个:查找快(比链表),添加,删除快(比数组): BST:二 ...
- 线索化二叉树的构建与先序,中序遍历(C++版)
贴出学习C++数据结构线索化二叉树的过程, 方便和我一样的新手进行测试和学习 同时欢迎各位大神纠正. 不同与普通二叉树的地方会用背景色填充 //BinTreeNode_Thr.h enum Point ...
- ID3算法 决策树 C++实现
人工智能课的实验. 数据结构:多叉树 这个实验我写了好久,开始的时候从数据的读入和表示入手,写到递归建树的部分时遇到了瓶颈,更新样例集和属性集的办法过于繁琐: 于是参考网上的代码后重新写,建立决策树类 ...
- 树形动态规划(树状DP)小结
树状动态规划定义 之所以这样命名树规,是因为树形DP的这一特殊性:没有环,dfs是不会重复,而且具有明显而又严格的层数关系.利用这一特性,我们可以很清晰地根据题目写出一个在树(型结构)上的记忆化搜索的 ...
- 【清北学堂2018-刷题冲刺】Contest 8
Task 1:关联点 [问题描述] ⼆叉树是⼀种常用的数据结构,⼀个⼆叉树或者为空,或者由根节点.左⼦树.右⼦树构成,其中左⼦树和右⼦树都是⼆叉树. 每个节点a 可以存储⼀个值val. 显然,如果 ...
- web(三)html标签
标签的层级特性 闭合的html标签内可以包含一个或多个子标签,因此html的标签是一个多叉树的数据结构,多叉树的根是html标签. 标签的属性描述 每个标签都具备一组公用或当前标签独有的属性,属性的作 ...
- 数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL
树.二叉树.三叉树.平衡排序二叉树AVL 一.树的定义 树是计算机算法最重要的非线性结构.树中每个数据元素至多有一个直接前驱,但可以有多个直接后继.树是一种以分支关系定义的层次结构. a.树是n ...
- Python Treelib 多叉树 数据结构 中文使用帮助文档
树,对于计算机编程语言来说是一个重要的数据结构.它具有广泛的应用,比如文件系统的分层数据结构和机器学习中的一些算法.这里创建了treelib来提供Python中树数据结构的高效实现. 官方文档:htt ...
随机推荐
- 深度学习概述教程--Deep Learning Overview
引言 深度学习,即Deep Learning,是一种学习算法(Learning algorithm),亦是人工智能领域的一个重要分支.从快速发展到实际应用,短短几年时间里, ...
- Unity推荐设置(HoloLens开发系列)
本文翻译自:Recommended settings for Unity Unity提供了一系列默认选项,这些选项能够适用于所有平台的一般情况.但是,Unity同样为HoloLens提供了一些特殊行为 ...
- uwp汉堡菜单的实现
---恢复内容开始--- 现在uwp上面的汉堡菜单(就是那个三道杠,点击之后会出现菜单)使用的越来越普遍,比如微软自己家的Cortana.现在我使用的实现方法是使用SplitView实现.首先Spli ...
- React Native v0.4 发布,用 React 编写移动应用
React Native v0.4 发布,自从 React Native 开源以来,包括超过 12.5k stars,1000 commits,500 issues,380 pull requests ...
- QML被系统缓存的原理是比较时间戳
Gunnar Roth January 25, 2017 at 17:07 Afaik the cached qml file contains a checksum of the original ...
- 常见的几个Qt编程问题的处理(转自QT中文论坛)(挺实用的)
1.如何在窗体关闭前自行判断是否可关闭答:重新实现这个窗体的closeEvent()函数,加入判断操作 void MainWindow::closeEvent(QCloseEvent*event){i ...
- Qt paintEvent绘制窗体 注意Qt::WA_PaintOutsidePaintEvent 只是适用于X11,其他系统均无效
QPainter默认只能在paintEvent里面调用,但是: 在其他事件中绘制窗体,提示信息如下:QPainter::begin: Paint device returned engine == 0 ...
- Mariadb的安装与使用
一.安装Mariadb 参考博客:https://www.cnblogs.com/pyyu/p/9467289.html 安装软件的三中方式 yum原码编译安装下载rpm安装 yum与原码编译安装安装 ...
- 30211Java_类
类 类:我们叫做class. 对象:叫做Object,instance(实例).某个类的对象,某个类的实例.是一样的意思.1.对象是具体的事物;类是对对象的抽象;2.类可以看成一类对象的模板,对象可以 ...
- 细谈unity资源加载和卸载
转载请标明出处:http://www.cnblogs.com/zblade/ 一.概要 在了解unity的资源管理方式之后,接下来细谈一下Unity的资源是如何从磁盘中加载到运行时的内存中,以及又是如 ...