对于二叉树遍历,递归实现与非递归实现在时间上有什么区别?
一、对于二叉树遍历,递归实现与非递归实现在时间上的区别
对于二叉树遍历,递归实现与非递归实现在时间上的区别是非递归比较容易搞内联,当然递归可以做尾递归优化,但二叉树遍历这样子的只能优化掉其中一处递归。
递归版本(先、中、后序)
递归版的遍历算法很简单了,我们只需要改变打印次序就好了,也没有什么可讲的!
// 递归版
// 先序遍历
void printPreorder1(TreeNode* head){
??? if (head == nullptr){
??????? return;
??? }
??? cout << head->value << ” “;
??? printPreorder1(head->left);
??? printPreorder1(head->right);
}
// 中序遍历
void printInorder1(TreeNode* head){
??? if (head == nullptr){
??????? return;
??? }
??? printInorder1(head->left);
??? cout << head->value << ” “;
??? printInorder1(head->right);
}
// 后序遍历
void printPostorder1(TreeNode* head){
??? if (head == nullptr){
??????? return;
??? }
??? printPostorder1(head->left);
??? printPostorder1(head->right);
??? cout << head->value << ” “;
}
非递归版本(先、中、后序)
首先我们要清楚,任何算法的递归版本都可以改成非递归版本,因为函数递归调用其实质就是压栈的过程,那么我们完全可以使用堆栈来模拟这个过程!
先序遍历
我们将数的每个节点压入栈中,由于是先序遍历,首先压入的是根节点,然后弹出(弹出节点时打印信息,且一个循环弹出一个节点),接着是压入右子树节点,最后压入左子树节点。为什么要这样呢?由于堆栈是“先进后出”结构,我们想要先打印左子树,因此最后压入左子树,循环这个过程,就达到了我们的目的。
// 迭代版
void printPreorder2(TreeNode* head){
??? cout << “Pre Order:” << endl;
??? if (head != nullptr){
??????? stack
??????? sta->push(head);
??????? TreeNode* cur = head;
??????? while(!sta->empty()){
??????????? cur = sta->较好();
??????????? sta->pop();
??????????? cout << cur->value << ” “;
??????????? if (cur->right != nullptr){
??????????????? sta->push(cur->right);
??????????? }
??????????? if (cur->left != nullptr){
??????????????? sta->push(cur->left);???? // 先压右边节点,再压左边节点,这与栈的特性有关
??????????? }
??????? }
??? }
??? cout << endl;
}
中序遍历
中序时,我们首先去遍历二叉树的左分支,并将节点压入栈中,只到找到最左边的叶节点,接着弹出(并打印节点),并看其有没右分支,如果没有,栈再弹出一个节点(根节点),看其有没有右分支。每次弹出,都要观察其是否有右分支,也就是说每个节点都遍历了两次!
void printInorder2(TreeNode* head){
???? cout << “In Order:” << endl;
???? if(head != nullptr){
???????? stack
???? ????TreeNode* cur = head;
???????? while(!sta->empty() || cur != nullptr){
???????????? if(cur != nullptr){
??????????????? sta->push(cur);
??????????????? cur = cur->left;
???????????? }else{
??????????????? cur = sta->较好();
??????????????? sta->pop();
??????????????? cout << cur->value << ” “;
??????????????? cur = cur->right;
???????????? }
???????? }
???? }
???? cout << endl;
}
后序遍历
后序遍历在意思上和前序遍历相近,而前序遍历的压栈顺序为:根、右、左。那么如果我们使用两个堆栈,名列前茅个压栈顺序为:根、左、右,但是在(先序遍历时)弹出根节点时将根节点压入第二个堆栈,为什么这里压栈顺序要为左右呢?很简单,在名列前茅个堆栈中最后压入右子树,那么右子树会最先压入第二个堆栈,相应的,当第二个堆栈弹出时,右子树会在左子树的后面弹出(先进后出)。注意:根节点是最先被压入名列前茅个栈中的,同时也是最先被压入第二个栈中的!
void printPostorder2(TreeNode* head){
??? cout << “Post Order:” << endl;
??? if (head != nullptr){
??????? stack
??????? stack
??????? TreeNode* cur = head;
??????? sta1->push(cur);
??????? while(!sta1->empty()){
?????? ?????cur = sta1->较好();
??????????? sta1->pop();????? // 弹出的是最晚被压入栈的数据
??????????? sta2->push(cur);
??????????? if(cur->left != nullptr){
??????????????? sta1->push(cur->left);
??????????? }
??????????? if(cur->right != nullptr){
??????????????? sta1->push(cur->right);
??????????? }
??????? }
??????? while(!sta2->empty()){
??????????? cur = sta2->较好();
??????????? sta2->pop();
??????????? cout << cur->value << ” “;
??????? }
??? }
??? cout << endl;
}
延伸阅读:
二、二叉数的概念和分类
二叉树是每个树节点非常多有两个子树的一种特殊的树结构,其有一些内在的性质,比如,若二叉树的层次从0开始,则在二叉树的第i层至多有2i个节点(i>=0),高度为k的二叉树非常多有2k+1?1个节点(空树的高度为-1)。其类别为以下几种:
满二叉树:所有的叶节点全部在底层,并且在底层全部铺满的二叉树完全二叉树:叶节点只能出现在最后两层,并且最底层的叶节点都向左对齐二叉搜索树:要求每个节点本身大于其左子树,而小于其右子树,对其进行中序遍历后,会得到一个有序的列表,这是我们经常用到的一种数的结构平衡二叉树:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,并且满足二叉搜索树的规则。
相关推荐HOT
更多>>
有哪些不同类型的 API?
一、API的类型API 根据其架构和使用范围进行分类。1、私有 API这类 API 面向企业内部,仅用于连接企业内的系统和数据。2、公有 API?这类 API ...详情>>
2023-10-14 23:46:39
Python的优缺点有哪些?
一、Python的优点1、简单易学Python的语法简单明了,易于理解和学习,非常适合初学者。2、丰富的第三方库Python拥有丰富的第三方库,可以快速开...详情>>
2023-10-14 20:19:16
B+树查询的稳定性为什么重要?
一、B+树查询的稳定性为什么重要首先最大的优势还是磁盘IO和范围,从我个人的看法看,稳定性(每次查询必须从根走到叶子节点)这意味行为可预估...详情>>
2023-10-14 17:40:38
进程如何找到pgd页表,页表的数据结构是什么?
一、进程找到pgd页表的方法在Linux内核中,每个进程都有一个指向其PGD的指针pgd,该指针位于进程描述符结构体(task_struct)中。进程可以通过...详情>>
2023-10-14 17:24:21热门推荐
有哪些不同类型的 API?
沸区块链的工作原理是什么?
热为什么 CIS Benchmarks 非常重要?
热为什么应使用 Docker?
新负载均衡有哪些优势?
使用 XML 有哪些好处??
python 在cmd 下执行脚本语句和在python shell 中的>>>下执行语句有什么区别?
Fortran语言中read*,和read(*,*)的区别?
边缘计算与CDN的区别是什么?
Django限制用户上传文件格式与大小的优异处理方式是什么?
Python单引号与双引号区别?
为什么iOS始终不支持应用双开深度分析给你答案?
高并发、高吞吐是什么?
Python的优缺点有哪些?
技术干货






