欢迎来到爱乐透手机选号_爱乐透官网_爱乐透旧版本下载! 联系我们 网站地图

爱乐透手机选号_爱乐透官网_爱乐透旧版本下载

0379-65557469

爱乐透
全国服务热线
0379-65557469

电话: 0379-65557469
0379-63930906
0379-63900388 
0379-63253525   
传真: 0379-65557469
地址:洛阳市洛龙区开元大道219号2幢1-2522、2501、2502、2503、2504、2505室 

爱乐透
当前位置: 首页 | 公司介绍 > 爱乐透

爱乐透手机选号-C++ 智能指针和二叉树:图解层序遍历和逐层打印二叉树

作者:admin 发布时间:2019-05-10 19:56:57 浏览次数:295
打印 收藏 关闭
字体【
视力保护色

来历:apocelipes

www.cnblogs.com/apocelipes/p/10758692.html

二叉树是极为常见的数据结构,关于怎么遍历其间元素的文章更是不计其数。

可是大多数文章都是解说的前序/中序/后序遍历,有关逐层打印元素的文章并不多,已有文章的解说也较为不流畅读起来茫无头绪。本文将用形象的图片加上明晰的代码协助你了解层序遍历的完结,一起咱们运用现代c++供给的智能指针来简化树形数据结构的资源办理。

那么现在让咱们进入正题。

运用智能指针构建二叉树

咱们这儿所要完结的是一个简略地模拟了二叉查找树的二叉树,供给契合二叉查找树的要求的刺进功用个中序遍历。一起咱们运用shared_ptr来办理资源。

现在咱们只完结insert和ldr两个办法,其他办法的完结并不是本文所关怀的内容,不过咱们会在后续的文章中逐一介绍:

struct BinaryTreeNode: publicstd::enable_shared_from_this<BinaryTreeNode> {

explicit BinaryTreeNode( constint value = 0)

: value_{value}, left{std::shared_ptr<BinaryTreeNode>{}}, right{std::shared_ptr<BinaryTreeNode>{}}

{}

void insert( constint value)

{

if(value < value_) {

if(left) {

left->insert(value);

} else{

left = std::make_shared<BinaryTreeNode>(value);

}

}

if(value > value_) {

if(right) {

right->insert(value);

} else{

right = std::make_shared<BinaryTreeNode>(value);

}

}

}

// 中序遍历

void ldr()

{

if(left) {

left->ldr();

}

std::cout << value_ << "n";

if(right) {

right->ldr();

}

}

// 分层打印

void layer_print();

int value_;

// 左右子节点

std::shared_爱乐透手机选号-C++ 智能指针和二叉树:图解层序遍历和逐层打印二叉树ptr<BinaryTreeNode> left;

std::shared_ptr<BinaryTreeNode> right;

private:

// 层序遍历

std::vector<std::shared_ptr<BinaryTreeNode>> layer_contents();

};

咱们的node目标承继自enable_shared_from_this,一般这不是有必要的,可是为了在层序遍历时便利操作,咱们需求从this结构智能指针,因而这步是有必要的。insert会将比root小的元素刺进左子树,比root大的刺进到右子树;ldr则是最为惯例的中序遍历,这儿完结它是为了以惯例办法检查tree中的一切元素。

值得留意的是,关于node节点咱们最好运用make_shared进行创立,而不是将其初始化为大局/部分目标,否则在层序遍历时会由于shared_ptr的析构然后导致目标被毁掉,然后引发未定义行为。

现在假定咱们有一组数据:[3, 1, 0, 2, 5, 4, 6, 7],将榜首个元素作为root,将一切数据刺进咱们的树中会得到如下的一棵二叉树:

auto root = std::make_shared<BinaryTreeNode>( 3);

root->insert( 1);

root->insert( 0);

root->insert( 2);

root->insert( 5);

root->insert( 4);

root->insert( 6);

root->insert( 7); 能够看到节点总共分成了四层,现在咱们需求逐层打印,该怎么做呢?

层序遍历

其实思路很简略,咱们选用广度优先的思路,先将节点的孩子都打印,然后再去打印子节点的孩子。

以上图为例,咱们先打印根节点的值3,然后咱们再打印它的一切子节点的值,是1和5,然后是左右子节点的子节点,以此类推。。。。。。

说起来很简略,可是代码写起来却会遇到费事。咱们不能简略得像中序遍历时那样运用递归来解决问题(事实上能够用改善的递归算法),由于它会直接来到叶子节点处,这不是咱们想要的成果。不过没关系,咱们能够借爱乐透手机选号-C++ 智能指针和二叉树:图解层序遍历和逐层打印二叉树助于行列,把子节点行列增加到行列结尾,然后从行列最初也便是根节点处遍历,将其子节点增加进行列,随后再对第二个节点做相同的操作,遇到一行完毕的当地,咱们运用nullptr做符号。

先看详细的代码:

std:: vector< std:: shared_ptr<BinaryTreeNode>>

BinaryTreeNode::layer_contents()

{

std:: vector< std:: shared_ptr<BinaryTreeNode>> nodes;

// 先增加根节点,根节点自己就会占用一行输出,所以增加了作为行分隔符的nullptr

// 由于需求保存this,所以这是咱们需求承继enable_shared_from_this是理由

// 相同是由于这儿,当回来的成果容器析构时this的智能指针也会析构

// 假如咱们运用了部分变量则this的引证计数从1减至0,导致目标被毁掉,而运用了make_shared创立的目标引证计数是从2到1,没有问题

nodes.push_back(shared_from_this());

nodes.push_back( nullptr);

// 咱们运用index而不是迭代器,是由于增加元素时很或许发作迭代器失效,处理这一问题将会消耗很多精力,而index则无此烦恼

for( intindex = 0; index < nodes.size(); ++index) {

if(!nodes[index]) {

// 子节点打印完结或现已遍历到行列结尾

if(index == nodes.size() -1) {

break;

}

nodes.push_back( nullptr); // 增加分隔符

continue;

}

if(nodes[index]->left) { // 将当时节点的子节点都增加进行列

nodes.push_back(nodes[index]->left);

}

if(nodes[index]->right) {

nodes.push_back(nodes[index]->right);

}

}

returnnodes;

}

代码自身并不杂乱,重要的是其背面的思维。

算法图解

假如你榜首遍并没有读懂这段代码也没关系,下面咱们有请图解上线:

首先是循环开端时的状况,榜首行的内容现已确认了(^代表空指针):

然后咱们从首元素开端遍历,榜首个遍历到的是root,他有两个孩子,值分别是1和5:

接着索引值+1,这次遍历到的是nullptr,由于不是在行列结尾,所以咱们简略增加一个nullptr在行列结尾,这样第二行的节点就都在行列中了:

随后咱们开端遍历第二行的节点,将它们的子节点作为第三行的内容放入行列,最终加上一个行分隔符,以此类推:

简略来说,便是经过行列来缓存上一行的一切节点,然后再依据上一行的缓存得到下一行的一切节点,循环往复直到二叉树的最终一层。当然不仅仅二叉树,其他多叉树的层序遍历也能够用相似的思维完结。

好了,知道了怎么获取每一行的内容,咱们就能逐行处理节点了:

voidBinaryTreeNode::la爱乐透手机选号-C++ 智能指针和二叉树:图解层序遍历和逐层打印二叉树yer_print()

{

autonodes = layer_contents();

for( autoiter = nodes.begin(); iter != nodes.end(); ++it黄色视屏er) {

// 空指针代表一行完毕,这儿咱们遇到空指针就输出换行符

if(*iter) {

std:: cout<< (*iter)->value_ << " ";

} else{

std:: cout<< "n";

}

}

}

如你所见,这个办法满足简略,咱们把节点信息保存在额定的容器中是为了便利做进一步的处理,假如仅仅打印的话大可不必这么费事,不过简略一般是有价值的。关于咱们的完结来说,分隔符的存在简化了咱们对层级之间的区别,可是这样会导致糟蹋至少log2(n)+1个vector的存储空间,某些情况下或许引起功用问题,并且经过合理得运用计数变量能够防止这些额定的空间糟蹋。当然详细的完结读者能够自己应战一下,原理和咱们上面介绍的是相似的因而就不在赘述了,也能够参阅园内其他的博客文章。

测验

最终让咱们看看完好的测验程序,记住要用make_shared创立root实例:

int main()

{

auto root = std::make_shared<BinaryTreeNode>( 3);

root->insert( 1);

root->insert( 0);

root->insert( 2);

root->insert( 5);

root->insert( 4);

root->insert( 6);

root->insert( 7);

root->ldr();

std::cout << "n";

root->layer_print();

}

输出:

能够看到上半部分是中序遍历的成果,下半部分是层序遍历的输出,并且是逐行打印的,不过咱们没有做缩进。所以不太漂亮。

别的你或许现已发现了,咱们没有写任何有关资源开释的代码,没错,这便是智能指针的威力,只需留意资源的创立,剩余的事都能够放心得交给智能指针处理,咱们能够把更多的精力会集在算法和功用的完结上。

智能指针和层序遍历的内容到这儿就完毕了,鄙人一篇文章中咱们还将看到智能指针和二叉树的更多操作。

好文章,我在看❤️

声明:该文观念仅代表作者自己,搜狐号系信息发布渠道,搜狐仅供给信息存储空间服务。

版权所有:洛阳市建设工程咨询有限责任公司 联系人:李经理 电话: 地址:洛阳市洛龙区开元大道219号2幢1-2522、2501、2502、2503、2504、2505室
版权所有 爱乐透手机选号 陕ICP备144566204号-9