文章目录

  • 前言
  • 思路
    • 设计思想
    • 非递归前序遍历的思路
    • 非递归中序遍历的思路
    • 非递归后序遍历的思路
    • 层序遍历的思路
  • 完整代码
    • MyBinaryTree.h
    • MyBinaryTree.cpp
    • Main.cpp
    • 效果展示

前言

  • 作者水平有限,全部的代码是学习前人+部分原创
  • 不要搬代码,一定要借鉴学习,自己动手!!!

思路

设计思想

  • 二叉树的创建:采用先序遍历的顺序,依次写出每个非空节点的数值,如果没有孩子节点就用$符号代替。并采用递归的方式进行实现,依次创建根节点、所有的左子树、右子树
  • 二叉树的前、中、后序的递归遍历:本质上的遍历顺序都是一样的,只是打印的时机不同,控制好打印的时机即可。

非递归前序遍历的思路

  1. 栈s初始化;
  2. 循环直到p为空且栈s为空
    • 当p不空时循环

      • 输出p->data;
      • 将指针p的值保存到栈中;
      • 继续遍历p的左子树
    • 当p为空,栈s不空,则
      • 将栈顶元素弹出至p;
      • 准备遍历p的右子树;

非递归中序遍历的思路

  1. 栈s初始化;
  2. 访问左孩子,左孩子存在继续步骤1;
  3. 左孩子不存在弹出函数栈帧;
  4. 访问右孩子,右孩子存在继续步骤1;
  5. 右孩子不存在弹出函数栈帧,访问该节点;
  6. 弹出函数栈帧,返回上一级函数栈帧。

非递归后序遍历的思路

  • 从当前节点开始遍历:

    1. 若当前节点存在,就存入栈中,并且置节点flag为1(第一次访问),然后访问其左子树;
    2. 直到当前节点不存在,需要回退,这里有两种情况:
      • 当栈顶节点flag为0时,则表明是从左子树回退,这时需置栈顶节点flag为2(第二次访问),然后通过栈顶节点访问其右子树(取栈顶节点用,但不出栈)
      • 当栈顶节点flag为1时,则表明是从右子树回退,这时需出栈,并取出栈节点做访问输出。
    3. 不断重复12,直到当前节点不存在且栈空。

层序遍历的思路

  • 从上到下,从左到右,则利用队列存放各子树结点的指针,初始时把根节点入队,当根结点出队后,令其左、右孩子结点入队(空不入队),而左孩子出队时又令它的左右孩子结点入队,……由此便可产生按层次输出的效果。

完整代码

MyBinaryTree.h

#pragma once
#include<iostream>
using namespace std;
typedef char E;
typedef struct TreeNode {E element;struct TreeNode* left, * right;// 在后序遍历时,需要左右子树都被遍历才行,0表示左子树遍历完成,1表示右子树遍历完成int flag;//标志遍历的状态。
}*Node;//栈
typedef Node T;//二叉树节点指针
typedef struct StackNode {T element;struct StackNode* next;
} *SNode;//队列
typedef struct QueueNode {T element;struct QueueNode* next;
}*QNode;typedef struct Queue {QNode front, rear;
}*LinkedQueue;Node createBiTree(Node& root);//按照先序顺序创建二叉树void preOrder(Node root);//递归方式进行先序遍历
void inOrder(Node root);//递归方式进行中序遍历
void postOrder(Node root);//递归方式进行后序遍历//栈操作
void initStack(SNode head);//初始化栈
int pushStack(SNode head, T element);//入栈
int IsEmpty(SNode head);//判断栈是否为空
T peekStack(SNode head);//获取栈顶元素值
T popStack(SNode head);//出栈void preOrder2(Node root);//非递归先序遍历
void inOrder0(Node root);//非递归中序遍历 低级版
void inOrder2(Node root);//非递归中序遍历 升级版
void postOrder2(Node root);//非递归后序遍历//队列操作
int initQueue(LinkedQueue queue);//初始化队列
int offerQueue(LinkedQueue queue, T element);//入队列
int isEmpty(LinkedQueue queue);//队列判空
T pollQueue(LinkedQueue queue);//出队
void levelOrder(Node root);//层序遍历
int getDepthTreeNode(Node root);//求二叉树的深度

MyBinaryTree.cpp

#include"MyBinaryTree.h"//创建二叉树
//注意采用引用的方式,避免浅拷贝的报错
//Program received signal SIGSEGV, Segmentation fault
Node createBiTree(Node& root) {char ch;cin >> ch;if (ch == '$') {root = NULL;}else {root = (Node)malloc(sizeof(struct TreeNode));root->element = ch;createBiTree(root->left);//构建左子树createBiTree(root->right);//构建右子树}return root;
}//递归方式进行先序遍历
void preOrder(Node root) {if (root != NULL) {cout << root->element << " ";preOrder(root->left);preOrder(root->right);}
}//递归方式进行中序遍历
void inOrder(Node root) {if (root == NULL) return;inOrder(root->left);cout << root->element << " ";inOrder(root->right);
}//递归方式进行后序遍历
void postOrder(Node root) {if (root == NULL) return;postOrder(root->left);postOrder(root->right);cout << root->element << " ";
}//初始化栈
void initStack(SNode head) {head->next = NULL;
}//入栈
int pushStack(SNode head, T element) {SNode node = (SNode)malloc(sizeof(struct StackNode));if (node == NULL) return 0;node->next = head->next;node->element = element;//element都是节点head->next = node;return true;
}//判空
int IsEmpty(SNode head) {return head->next == NULL;
}//用于获取栈顶元素的值,但是不出栈,仅仅是值获取
T peekStack(SNode head) {return head->next->element;//返回栈中的首节点的地址
}//出栈
T popStack(SNode head) {SNode top = head->next;head->next = head->next->next;T e = top->element;free(top);return e;
}//非递归实现
//先序遍历
void preOrder2(Node root) {struct StackNode stack;initStack(&stack);//两个条件,只有当栈为空并且节点为NULL时才终止循环while (root || !IsEmpty(&stack)) {//先不断遍历左子树,直到没有为止while (root) {cout << root->element << " ";//然后打印当前节点的元素值pushStack(&stack, root);//每遇到一个节点,就将节点入栈root = root->left;//继续遍历下一个左孩子节点}Node node = popStack(&stack);//经过前边的遍历,明确左子树全部走完了,就进行右子树的遍历//得到右孩子,如果有右孩子,下一轮会重复上面的步骤;如果没有右孩子,那么这里的root就会变成null,// 下一轮开始会直接跳过上面的while,继续出栈下一个节点,再找右子树root = node->right;}
}
//中序遍历二叉树的非递归算法:没有让空指针进栈
void inOrder2(Node root) {struct StackNode stack;initStack(&stack);//两个条件,只有当栈为空并且节点为NULL时才终止循环while (root || !IsEmpty(&stack)) {//先不断遍历左子树,直到没有为止while (root) {pushStack(&stack, root);//每遇到一个节点,就将节点入栈root = root->left;//继续遍历下一个左孩子节点}Node node = popStack(&stack);//经过前边的遍历,明确左子树全部走完了,就进行右子树的遍历cout << node->element << " ";//然后打印当前节点的元素值//得到右孩子,如果有右孩子,下一轮会重复上面的步骤;如果没有右孩子,那么这里的root就会变成null,// 下一轮开始会直接跳过上面的while,继续出栈下一个节点,再找右子树root = node->right;}
}
//中序遍历二叉树的非递归算法:让空指针进栈
void inOrder0(Node root) {struct StackNode stack;initStack(&stack);T p;pushStack(&stack, root);//根指针入栈while (!IsEmpty(&stack)) {//有栈顶元素 ,并且节点不为NULLwhile ((p = peekStack(&stack)) && p) {pushStack(&stack, p->left);//向左走到尽头}//直到左孩子为NULL,此时栈顶为整棵树最左边的节点,将NULL进栈,循环结束//弹出栈顶空节点NULL ,因为子孩子为NULL,不需要打印值p = popStack(&stack);//空指针退栈if (!IsEmpty(&stack)) {//栈不为空,访问节点,向右一步//弹出最上面的节点 ,也就是逻辑中序第一个节点p = popStack(&stack);cout << p->element << " ";pushStack(&stack, p->right);//如果有右孩子,则右孩子进栈,,接着以右孩子为逻辑根节点来中序遍历,判断右孩子是否有左孩子和右孩子....//如果没有右孩子,就将NULL压进栈,下次循环会被弹出并不打印}}
}//后序遍历
void postOrder2(Node root) {struct StackNode stack;initStack(&stack);while (root || !IsEmpty(&stack)) {while (root) {pushStack(&stack, root);root->flag = 0;//首次入栈,只能代表左子树遍历完成,所以设置flag为0root = root->left;}root = peekStack(&stack);//获取节点if (root->flag == 0) {//如果仅仅遍历左子树,那么flag就等于0root->flag = 1;//此时标记为1表示遍历右子树root = root->right;}else {cout << root->element << " ";//当flag为1时,表示左右都遍历完成,这时再将值打印出来popStack(&stack);//这时再把对应的节点出栈,因为左右都遍历完了root = NULL;//置NULL,下一轮直接跳过while,然后继续取栈中剩余的节点,重复上述操作}}
}//初始化对列
int initQueue(LinkedQueue queue) {//设置头节点,并将队头和队尾同时指向头节点QNode node = (QNode)malloc(sizeof(struct QueueNode));if (node == NULL) return 0;queue->front = queue->rear = node;return true;
};//入队
int offerQueue(LinkedQueue queue, T element) {//入队,将新的节点入队放在队尾,并修改rear的指向QNode node = (QNode)malloc(sizeof(struct QueueNode));if (node == NULL) return 0;node->element = element;queue->rear->next = node;queue->rear = node;return true;
}//判空
int isEmpty(LinkedQueue queue) {//当队头和队尾指针同时指向同一个节点时,说明队列为空队列return queue->front == queue->rear;
}//出队
T pollQueue(LinkedQueue queue) {//queue->front —— 头节点//queue->front->next->element --队头结点中存储的节点的地址T e = queue->front->next->element;//queue->front->next --队头QNode qNode = queue->front->next;//更新链队列头节点queue->front->next = queue->front->next->next;//qNode=qNode->next;//如果队列中只有一个节点,将队尾指针指向设置好的头节点if (queue->rear == qNode) queue->rear = queue->front;free(qNode);//返回删除的旧的队头节点的节点地址,并没有物理删除,只是释放队列的节点空间return e;
}//层序遍历
void levelOrder(Node root) {struct Queue queue;//创建队列initQueue(&queue);offerQueue(&queue, root);//先把根节点入队while (!isEmpty(&queue)) {Node node = pollQueue(&queue);cout << node->element << " ";if (node->left) //如果左、右孩子,依次将左、右孩子入队offerQueue(&queue, node->left);if (node->right)offerQueue(&queue, node->right);}
}//求二叉树的深度
int getDepthTreeNode(Node root) {if (root == NULL) {return 0;}else {int lLength = getDepthTreeNode(root->left);int rlength = getDepthTreeNode(root->right);int max = rlength > lLength ? (rlength + 1) : (lLength + 1);return max;}
};

Main.cpp

#include"MyBinaryTree.h"
int main() {cout << "1--创建二叉树" << endl;cout << "2--先序遍历二叉树【递归方式】" << endl;cout << "3--中序遍历二叉树【递归方式】" << endl;cout << "4--后序遍历二叉树【递归方式】" << endl;cout << "5--先序遍历二叉树【非递归方式】" << endl;cout << "6--中序遍历二叉树【非递归方式1】" << endl;cout << "7--中序遍历二叉树【非递归方式2】" << endl;cout << "8--后序遍历二叉树【非递归方式】" << endl;cout << "9--层序遍历二叉树" << endl;cout << "10--求二叉树的深度" << endl;cout << "-1--退出" << endl;int option;Node t;//定义一个Node的指针t = NULL;//不进行初识,就会报错do {cout << "请输入选择:";cin >> option;switch (option){case 1:cout << "请按先序输入二叉树中节点的值(一个字符)$字符表示空树:";t = createBiTree(t);if (t) {cout << "创建二叉树成功!" << endl;}break;case 2:cout << "前序遍历【递归实现】:";preOrder(t);cout << endl;break;case 3:cout << "中序遍历二叉树【递归方式】";inOrder(t);cout << endl;break;case 4:cout << "后序遍历二叉树【递归方式】";postOrder(t);cout << endl;break;case 5:cout << "先序遍历二叉树【非递归方式】";preOrder2(t);cout << endl;break;case 6:cout << "中序遍历二叉树【非递归方式1】";inOrder0(t);cout << endl;break;case 7:cout << "中序遍历二叉树【非递归方式2】";inOrder2(t);cout << endl;break;case 8:cout << "后序遍历二叉树【非递归方式】";postOrder2(t);cout << endl;break;case 9:cout << "层序遍历二叉树【非递归实现】";levelOrder(t);cout << endl;break;case 10:cout << "二叉树的深度为:";cout << getDepthTreeNode(t) << endl;break;case -1:cout << "谢谢使用!再见!" << endl;return 0;default:cout << "请输入正确的操作!";break;}} while (option != -1);
}

效果展示


二叉树先、中、后遍历递归+非递归相关推荐

  1. 详细图解二叉树中序遍历(非递归C++)LeetCode94

    详细图解二叉树中序遍历(非递归) 二叉树中序递归含义 LeetCode题目94 详细图解 源代码 运行结果 二叉树中序递归含义 中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树.若二叉树为空则结 ...

  2. 二叉树的先序遍历和非递归遍历

    #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Mon May 13 15:48:30 201 ...

  3. JAVA 中序遍历的非递归栈实现

    题目描述 请实现一个函数,检查一棵二叉树是否为二叉查找树. 给定树的根结点指针TreeNode* root,请返回一个bool,代表该树是否为二叉查找树. import java.util.*;/* ...

  4. 二叉树的先序遍历(非递归)

    虽然递归简单理解,但是用递归内存开销大,耗时长,性能往往不如非递归方式 所以这里通过栈,用非递归方法实现二叉树的先序遍历 二叉树的存储结构定义: typedef struct node{int dat ...

  5. 二叉树的四种遍历(非递归)

    class treeNode:def __init__(self, val, left=None, right=None):self.val = valself.left = leftself.rig ...

  6. 二叉树(先序遍历)非递归

    为什么80%的码农都做不了架构师?>>>    #include <iostream> #include <stack>struct Node {int da ...

  7. 二叉树前序、中序和后序遍历的非递归实现

    1 二叉树的遍历 1.1 前序遍历 对于每棵子树,先处理根,然后处理左子树,最后处理右子树.根最先访问,所以是前序遍历. 1.2 中序遍历 对于每棵子树,先处理左子树,然后处理根,最后处理右子树.根中 ...

  8. 二叉树的遍历(非递归)整理

    二叉树的遍历(非递归) 写在前面 二叉树重要,重要,重要.以下代码每日手撸一遍,深刻理解. 二叉树的先序遍历(非递归) 巧记心法 判断是否为空树 1.右侧入栈(访问,q指向右孩子,不空则入栈) 2.p ...

  9. 94. 二叉树的中序遍历-M

    94. 二叉树的中序遍历 label: 非递归中序遍历,LNR,字节跳动面试题 给定一个二叉树,返回它的中序 遍历. 示例: 输入: [1,null,2,3] 1\2/3 输出: [1,3,2] 进阶 ...

  10. 二叉树前中后序遍历的非递归实现以及层次遍历、zig-zag型遍历详解

    前言 二叉树的遍历是一个比较常见的问题,递归实现二叉树的前中后序遍历比较简单,但非递归实现二叉树的前中后序遍历相对有难度.这篇博客将详述如何使用非递归的方式实现二叉树的前中后序遍历,在进行理论描述的同 ...

最新文章

  1. 【opencv】丁达尔效应
  2. 用dedecms自定义表单创建简易自助预约系统
  3. 不知因果,何以谈优化?
  4. 游戏中用到的设计模式
  5. ImageView相关
  6. 2021瑞安高考成绩查询,温州教育网官网登录入口2021瑞安中考成绩查询中招查分系统...
  7. html高度的属性的值,html – 行高属性是否可以继承父Div的高度属性或其所属Div的访问高度属性?...
  8. SAP License:SAP PM的应用从实施开始
  9. X86汇编语言从实模式到保护模式08:中断和动态时钟显示
  10. python os
  11. android 通过usb验证应用,Linux应用可通过USB访问Android设备-Chrome OS 75版发布
  12. linux中级之lvs配置(命令)
  13. 5.2刚买了佳能的ixus100is数码相机,可以录像不过是mov格式的,需要转换为dvd的软件...
  14. Lync Server 2010 客户端访问提示验证服务器中的证书时遇到问题解决方法
  15. 开关灯问题 BulbSwitch
  16. visio画图复制粘贴到word_怎么将visio绘图导入Word(visio绘图插入word后如何调整大小)...
  17. 湖北省大数据发展行动计划(2016-2020年)
  18. hdu-4747(线段树)
  19. 工业大数据收集及预测建模方法(南京大学-宋哲博士分享)- 个人总结
  20. 实现调用阿里云API第一章——API请求与认证

热门文章

  1. ElasticSearch 5. 搭建ES集群
  2. 【JavaEE初阶】第八节.网络原理网络层和数据链路层,应用层
  3. 音视频 FFmpeg
  4. 第十五次Java作业
  5. vim 查找并替换多个匹配字符
  6. 常用PCB快捷键总结
  7. 工具网站推荐 - DLL‑FILES.COM帮你找到你的应用程序所缺失的dll文件
  8. 目前国内几大著名报表软件(2014更新)
  9. 获取国庆放假加班信息(记录)
  10. 基于pt100的温度测量系统设计 c语言程序 四臂电桥,基于PT100的温度测量系统设计毕业论文.DOC...