c语言中二叉树中总结点,C语言二叉树的三种遍历方式的实现及原理

二叉树遍历分为三种:前序、中序、后序,其中序遍历最为重要。为啥叫这个名字?是根据根节点的顺序命名的。

57d857b794cb23ac3b03bc7d7ee6a75a.png

比如上图正常的一个满节点,A:根节点、B:左节点、C:右节点,前序顺序是ABC(根节点排最先,然后同级先左后右);中序顺序是BAC(先左后根最后右);后序顺序是BCA(先左后右最后根)。

ab81855b43334ce5e7db0cef1e19a2df.png

比如上图二叉树遍历结果

前序遍历:ABCDEFGHK

中序遍历:BDCAEHGKF

后序遍历:DCBHKGFEA

分析中序遍历如下图,中序比较重要(java很多树排序是基于中序,后面讲解分析)

f9138ec7719e6f6682ce892313c4f11f.png

下面介绍一下,二叉树的三种遍历方式,其中每一种遍历方式都有三种实现方式。

节点定义:

struct TreeNode

{

int val;

TreeNode *left,*right;

TreeNode(int val){

this->val = val;

this ->left = this->right = NULL;

}

};

先序遍历

904aaa8ce7e2ee8b636f9b22e26ca598.png

以上面这张图为例:我们讲讲树的三种遍历方式:

先序遍历:先访问根节点,然后访问左孩子,最后访问右孩子。

所以,上面遍历的结果是:GEDACHS。

下面,我们来看看具体代码实现

1.递归实现

void preOrder(TreeNode *root){

if (root==NULL)

return;

cout<val<

preOrder(root->left);

preOrder(root->right);

}

2.使用辅助栈

实现思路:1.将根节点入栈

2.每次从栈顶弹出一个节点,访问该节点

3.把当前节点的右孩子入栈

4.把当前节点的左孩子入栈

具体实现:

void preOrder2(TreeNode *root){

if (root == NULL)

return;

stack stk; //开辟一个栈空间

stk.push(root);

while(!stk.empty()){

TreeNode* pNode = stk.pop();

cout<val;

if (pNode->right!=NULL)

stk.push(pNode->right);

if (pNode->left!=NULL)

stk.push(pNode->left);

}

}

3.Morris遍历

Morris遍历,常数的空间即可在O(n)时间内完成二叉树的遍历。

O(1)空间进行遍历困难之处在于在遍历的子结点的时候如何重新返回其父节点?

在Morris遍历算法中,通过修改叶子结点的左右空指针来指向其前驱或者后继结点来实现的。

其本质:线索二叉树(Threaded Binary Tree),通过利用叶子节点空的right指针,指向中序遍历的后继节点,从而避免了对 stack 的依赖。

具体实现:

void preOrder(TreeNode* root){

if (root == NULL)

return;

TreeNode* pNode = root;

while(pNode != NULL){

if (pNode->left == NULL)

{

cout<val<

pNode = pNode->right;

}

else{

TreeNode* pPre = pNode->left;

while(pPre->right != NULL && pPre->right != pNode){

pPre = pPre->right;

}

if (pPre->right == NULL)

{

/* code */

pPre->right = pNode;

cout<val<

pNode = pNode->left;

}

else{

pPre->right = NULL;

pNode = pNode->right;

}

}

}

}

中序遍历

中序遍历:先访问左孩点,然后访问根节点,最后访问右孩子。

所以,上面遍历的结果是:DEAGHCS。

下面,我们来看看具体代码实现

1.递归实现

void InOrder(TreeNode *root){

if (root==NULL)

return;

InOrder(root->left);

cout<val<

InOrder(root->right);

}

2.使用辅助栈

实现思路:

初始化一个二叉树结点pNode指向根结点;

若pNode非空,那么就把pNode入栈,并把pNode变为其左孩子;(直到最左边的结点)

若pNode为空,弹出栈顶的结点,并访问该结点,将pNode指向其右孩子(访问最左边的结点,并遍历其右子树)

具体实现:

void InOrder(TreeNode *root){

if (root==NULL)

{

return;

}

stack stk;

TreeNode *pNode = root;

while(pNode!=NULL || !stk.empty()){

if (pNode != NULL)

{

stk.push(pNode);

pNode = pNode->left;

}

else{

pNode = stk.pop();

stk.pop();

cout<val<

pNode = pNode->right;

}

}

}

3.Morris遍历

实现思路:

1.如果当前节点pNode的左孩子为空,那么输出该节点,并把该节点的右孩子作为当前节点

2.如果当前节点pNode的左孩子非空,那么找出该节点在中序遍历的前驱结点prev

当第一次访问该前驱结点prev时,其右孩子必定为空,那么就将其右孩子设置为当前结点,以便根据这个指针返回到当前结点pNode中,并将当前结点pNode设置为其左孩子;

当该前驱结点pPre的右孩子为当前结点,那么就输出当前结点,并把前驱结点的右孩子设置为空(恢复树的结构),将当前结点更新为当前结点的右孩子;

3.重复以上两步,直到当前结点为空。

具体实现:

void InOrder(TreeNode *root){

if (root == NULL)

return;

TreeNode* pNode = root;

while(pNode != NULL){

if (pNode->left == NULL)

{

cout<val<

pNode = pNode->right;

}

else{

TreeNode* pPre = pNode->left;

while(pPre->right != NULL && pPre->right != pNode){

pPre = pPre->right;

}

if (pPre->right == NULL)

{

/* code */

pPre->right = pNode;

pNode = pNode->left;

}

else{

pPre->right = NULL;

cout<val<

pNode = pNode->right;

}

}

}

}

后序遍历

后序遍历:先访问左孩子,然后访问右孩子,最后访问根节点。

所以,上面遍历的结果是:DAEHSCG。

下面,我们来看看具体代码实现:

1.递归实现

void PostOrder(TreeNode *root){

if (root==NULL)

return;

PostOrder(root->left);

PostOrder(root->right);

cout<val<

}

2.使用辅助栈

void postOrder(TreeNode *root) {

if(root == NULL)

return;

stack stk;

stk.push(root);

TreeNode *prev = NULL;

while(!stk.empty()) {

TreeNode *pNode = stk.top();

if(!prev || prev->left == pNode || prev->right == pNode) { // traverse down

if(pNode->left)

stk.push(pNode->left);

else if(pNode->right)

stk.push(pNode->right);

/* else {

cout << pNode->val << endl;

stk.pop();

}

*/

}

else if(pNode->left == prev) { // traverse up from left

if(pNode->right)

stk.push(pNode->right);

}

/* else if(pNode->right == prev) { // traverse up from right

cout << pNode->val << endl;

stk.pop();

}

*/

else {

cout << pNode->val << endl;

stk.pop();

}

prev = pNode;

}

}

双辅助栈实现思路:

设置两个栈stk, stk2;

将根结点压入第一个栈stk;

弹出stk栈顶的结点,并把该结点压入第二个栈stk2;

将当前结点的左孩子和右孩子先后分别入栈stk;

当所有元素都压入stk2后,依次弹出stk2的栈顶结点,并访问之。

第一个栈的入栈顺序是:根结点,左孩子和右孩子;于是,压入第二个栈的顺序是:根结点,右孩子和左孩子。

因此,弹出的顺序就是:左孩子,右孩子和根结点。

void PostOrder2(TreeNode *root){ //两个栈实现

if (root == NULL)

return;

stack stk,stk2;

stk.push(root);

while(!stk.empty()){

TreeNode* pNode = stk.top();

stk.pop();

stk2.push(pNode);// 将根节点压栈

if (pNode->left != NULL) // 如果左孩子不为空,则压栈

{

stk.push(pNode->left);

}

if (pNode->right != NULL) // 如果左孩子不为空,则压栈

{

stk.push(pNode->right);

}

}

while(!stk2.empty()){

cout<val<

stk2.pop();

}

}

3.Morris遍历实现

实现思路:

1.先建立一个临时结点dummy,并令其左孩子为根结点root,将当前结点设置为dummy;

2.如果当前结点的左孩子为空,则将其右孩子作为当前结点;

3.如果当前结点的左孩子不为空,则找到其在中序遍历中的前驱结点,

-如果前驱结点的右孩子为空,将它的右孩子设置为当前结点,将当前结点更新为当前结点的左孩子;

-如果前驱结点的右孩子为当前结点,倒序输出从当前结点的左孩子到该前驱结点这条路径上所有的结点。将前驱结点的右孩子设置为空,将当前结点更新为当前结点的右孩子。

4.重复以上过程,直到当前结点为空。

具体实现:

void reverse(TreeNode* p1,TreeNode *p2){

if (p1 == p2)

return;

TreeNode* x = p1;

TreeNode* y = p1->right;

while(true){

TreeNode* tmp = y->right;

y->right = x;

x = y;

y = tmp;

if (x == p2)

break;

}

}

void printReverse(TreeNode* p1,TreeNode *p2){

reverse(p1,p2);

TreeNode* pNode = p2;

while(true){

cout<val<

if (pNode == p1)

break;

pNode = pNode->right;

}

reverse(p2,p1);

}

void PostOrder3(TreeNode* root){

if(root == NULL)

return;

TreeNode *dummy = new TreeNode(-1);

dummy->left = root;

TreeNode *pNode = dummy;

while(pNode != NULL) {

if(pNode->left == NULL)

pNode = pNode->right;

else {

TreeNode *pPrev = pNode->left;

while(pPrev->right != NULL && pPrev->right != pNode)

pPrev = pPrev->right;

if(pPrev->right == NULL) {

pPrev->right = pNode;

pNode = pNode->left;

}

else {

printReverse(pNode->left, pPrev);

pPrev->right = NULL;

pNode = pNode->right;

}

}

}

}

总结

上述三种遍历方式时间复杂度和空间复杂度分析:

1.递归遍历和非递归遍历 时间复杂度0(n) 空间复杂度O(n)

2.Morris遍历 时间复杂度0(n) 空间复杂度O(1)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动态库的创建与使用

1、动态库文件的创建 &#xff08;1&#xff09;编写源文件 &#xff08;2&#xff09;编译生成动态库 g -fPIC -shared -o libfile_operation.so file_operation.cpp 此编译过程分为两步&#xff0c;等同于下面的两个命令&#xff1a; g -c -fPIC file_operation.cpp …

ux设计中的各种地图_UX写作中的移情

ux设计中的各种地图Demetri Martin is a master of comedic situations. If you’ve never seen Demetri Martin是喜剧情境的大师。 如果你从未见过 him before, he has a sort of dry brand of observational humor, relying more on anecdotes than full stories, and often…

字符串搜索。HOJ1530 Compound Words。

stl set实现字符串搜索。。效率一般。(附二分搜索。) Compound WordsTime limit:1sec.Submitted:233Memory limit:32MAccepted:81Source: Waterloo ACM Programming Contest Sep 28, 1996 You are to find all the two-word compound words in a dictionary. A two-word compo…

字节3-1前端面试官自学Vue的正确姿势

大家好&#xff0c;我是若川。前不久和一个字节前端TL朋友聊天&#xff0c;说到大厂前端供需脱节的情况。特别是使用Vue框架的&#xff0c;因为简单易学好上手&#xff0c;但是能够深入理解的人并不多&#xff0c;大多都只停留在应用层面&#xff0c;缺乏更深层面的理解。尤其是…

苹果风格ui_苹果如何使Soft-UI成为未来

苹果风格ui重点 (Top highlight)Apple announced some pretty wild updates at WWDC 2020 today.苹果今天在WWDC 2020上宣布了一些相当疯狂的更新。 But technology aside, let’s focus on how their UI has changed. It went through the first bitmap representations, thr…

【数据结构】量子危机

问题 宇宙时间公元 5.55 亿年&#xff0c;由于某种原因两大联盟展开了激战&#xff08;maxingc 联盟采用了微子技术&#xff09;&#xff1a; 邪恶的 maxingc 联盟采集好了微子能&#xff0c;就要运输。Maxingc 联盟的领袖 xc 此时才发现&#xff0c;自己的军事基地中由微子发射…

android 自定义menu背景,Android编程实现自定义系统菜单背景的方法

本文实例讲述了Android编程实现自定义系统菜单背景的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;不多说&#xff0c;上图&#xff0c;见代码。package lab.sodino.menutest;import android.content.Context;import android.app.Activity;import android.os.Bu…

面试官问 async、await 函数原理是在问什么?

大家好&#xff0c;我是若川。这是 源码共读活动《1个月&#xff0c;200人&#xff0c;一起读了4周源码》 第四期&#xff0c;纪年小姐姐的第四次投稿。纪年小姐姐通过本次学习提早接触到generator&#xff0c;协程概念&#xff0c;了解了async/await函数的原理等。第四期是 学…

一步步优化JVM六:优化吞吐量[转]

2019独角兽企业重金招聘Python工程师标准>>> 原文&#xff1a;http://ganlv.iteye.com/blog/1571315 参考&#xff1a;http://www.myexception.cn/software-architecture-design/1455594.html 现代JVM是一个具有灵活适应各种应用能力的软件&#xff0c;尽管很多应用…

element-ui 网格_UI备忘单:列表与网格

element-ui 网格重点 (Top highlight)Grids or lists? That is the question we will look at in this cheat sheet. While they can be used anywhere in your site, we are going to look primarily at search results, catalogs and newsfeeds. Making this choice will de…

50行 koa-compose,面试常考的中间件原理原来这么简单?

大家好&#xff0c;我是若川。源码共读《1个月&#xff0c;200人&#xff0c;一起读了4周源码》 活动第五期是学习 koa 源码的整体架构&#xff0c;浅析koa洋葱模型原理和co原理中的koa-compose源码原理&#xff0c;阅读不到50行的koa-compose源码。这篇是izjing小哥哥的投稿。…

sqlite3源码编译到Android,实现SQLite跨全平台使用

文&#xff0f;何晓杰Dev(高级Android架构师)著作权归作者所有&#xff0c;转载请联系作者获得授权。初看这个标题你可能会不解&#xff0c;SQLite 本身就是一个跨平台的数据库&#xff0c;在这里再说跨平台有什么意义呢&#xff1f;其实不然&#xff0c;目前我就遇到了一个项目…

illustrator下载_平面设计:16个Illustrator快捷方式可加快工作流程

illustrator下载I know, I know — keyboard shortcuts sound so nerdy, and you’re a graphic designer, not an IT Director, why should you learn keyboard shortcuts?我知道&#xff0c;我知道—键盘快捷键听起来很书呆&#xff0c;而且您是图形设计师&#xff0c;而不是…

手把手教你五分钟扒个源码写个无敌外挂

大家好&#xff0c;我是若川。源码共读《1个月&#xff0c;200人&#xff0c;一起读了4周源码》 活动进行到第五期了&#xff0c;欢迎点链接加我微信 ruochuan12 报名参加。前言前段时间群里分享了一个小游戏&#xff0c;多次怀疑自己的眼睛以后&#xff0c;尝试去写个外挂。中…

Kubernetes 1.14重磅来袭,多项关键特性生产可用

走过了突飞猛进的2018年&#xff0c;Kubernetes在2019年终于迎来了第一个大动作&#xff1a;Kubernetes 1.14版本的正式发布&#xff01;Kubernetes 本次发布的 1.14 版本&#xff0c;包含了 31 项增强&#xff0c;其中 10 项为 GA&#xff0c;12 项进入 beta 试用阶段&#xf…

open ai gpt_让我们来谈谈将GPT-3 AI推文震撼到核心的那条推文

open ai gpt重点 (Top highlight)“设计师”插件 (The ‘Designer’ plugin) A couple days ago, a tweet shared by Jordan Singer turned the heads of thousands of designers. With the capabilities of GPT-3 (from OpenAI), he shared a sample of what he was able to c…

我历时3年才写了10余篇源码文章,但收获了100w+阅读

你好&#xff0c;我是若川。最近来了一些读者朋友&#xff0c;在这里简单介绍自己的经历&#xff0c;也许对你有些启发。之前发过这篇文章&#xff0c;现在修改下声明原创&#xff0c;方便保护版权。最近组织了源码共读活动1个月&#xff0c;200人&#xff0c;一起读了4周源码&…

第 8 章 容器网络 - 061 - flannel 的连通与隔离

flannel 的连通与隔离 测试 bbox1 和 bbxo2 的连通性&#xff1a; bbox1 能够 ping 到位于不同 subnet 的 bbox2&#xff0c;通过 traceroute 分析一下 bbox1 到 bbox2 的路径。 1&#xff09; bbox1 与 bbox2 不是一个 subnet&#xff0c;数据包发送给默认网关 10.2.9.1&#…

计算机视觉笔记本推荐_视觉灵感:Mishti笔记本

计算机视觉笔记本推荐The Mishti Notebook is a project close to my heart, wherein I experimented with screen printing techniques at the Print Labs at the National Institute of Design, Ahmedabad. Dating back to the year 2012 when the NID Print Labs was first …

Google工程师:如何看待程序员普遍缺乏数据结构和算法知识?

出处&#xff1a;极客时间《数据结构与算法之美》很多技术人都很迷茫&#xff0c;觉得自己做的项目没有技术含量&#xff0c;成天就是卖苦力。技术的东西&#xff0c;日新月异&#xff0c;有些人总在忙于追求热点新技术&#xff0c;东学学、西学学&#xff0c;平时泛泛地看技术…