首页 > 编程语言 >二叉树的递归与非递归遍历:C++实现

二叉树的递归与非递归遍历:C++实现

时间:2024-08-16 20:52:35浏览次数:9  
标签:遍历 TreeNode 递归 C++ current 二叉树 left

在数据结构的学习中,二叉树是一个非常重要的概念。遍历二叉树是理解和操作二叉树的基础。本文将介绍如何使用C++实现二叉树的递归和非递归遍历,包括前序、中序和后序遍历,并对每种遍历方法的原理进行简要介绍。

二叉树节点定义

首先,我们定义一个简单的二叉树节点结构:

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

递归遍历二叉树

递归遍历是一种直观且易于实现的方法。以下是使用递归实现的前序、中序和后序遍历函数:

using namespace std;

// 递归前序遍历原理:首先访问根节点,然后递归遍历左子树,最后递归遍历右子树。
void preOrderRecursive(TreeNode* node) {
    if (node == nullptr) return;
    cout << node->val << " ";  // 访问当前节点
    preOrderRecursive(node->left);  // 遍历左子树
    preOrderRecursive(node->right); // 遍历右子树
}

// 递归中序遍历原理:首先递归遍历左子树,然后访问根节点,最后递归遍历右子树。
void inOrderRecursive(TreeNode* node) {
    if (node == nullptr) return;
    inOrderRecursive(node->left);  // 遍历左子树
    cout << node->val << " ";  // 访问当前节点
    inOrderRecursive(node->right); // 遍历右子树
}

// 递归后序遍历原理:首先递归遍历左子树,然后递归遍历右子树,最后访问根节点。
void postOrderRecursive(TreeNode* node) {
    if (node == nullptr) return;
    postOrderRecursive(node->left);  // 遍历左子树
    postOrderRecursive(node->right); // 遍历右子树
    cout << node->val << " ";  // 访问当前节点
}

非递归遍历二叉树

非递归遍历通常使用栈来实现。以下是使用非递归方法实现的前序、中序和后序遍历函数:

// 非递归前序遍历原理:使用栈模拟递归的压栈过程,首先遍历到树的最左端,然后逐个弹出节点并访问。
void preOrderNonRecursive(TreeNode* root) {
    stack<TreeNode*> stack;
    TreeNode* current = root;

    while (current != nullptr || !stack.empty()) {
        if (current != nullptr) {
            cout << current->val << " ";
            stack.push(current);
            current = current->left;
        } else {
            current = stack.top();
            stack.pop();
            current = current->right;
        }
    }
}

// 非递归中序遍历原理:使用栈记录遍历路径,首先遍历到最左端,然后回溯访问节点并继续遍历右子树。
void inOrderNonRecursive(TreeNode* root) {
    stack<TreeNode*> stack;
    TreeNode* current = root;

    while (current != nullptr) {
        stack.push(current);
        current = current->left;
    }

    while (!stack.empty()) {
        current = stack.top();
        stack.pop();
        cout << current->val << " ";
        current = current->right;
        while (current != nullptr) {
            stack.push(current);
            current = current->left;
        }
    }
}

// 非递归后序遍历原理:使用两个栈来分别记录节点的遍历顺序和访问顺序,以实现最后访问根节点。
void postOrderNonRecursive(TreeNode* root) {
    stack<TreeNode*> s1, s2;
    TreeNode* current = root;

    while (current != nullptr) {
        s1.push(current);
        current = current->left;
    }

    while (!s1.empty()) {
        current = s1.top();
        s1.pop();
        s2.push(current);
        if (current->right != nullptr) {
            current = current->right;
            while (current != nullptr) {
                s1.push(current);
                current = current->left;
            }
        }
    }

    while (!s2.empty()) {
        current = s2.top();
        s2.pop();
        cout << current->val << " ";
    }
}

测试代码

为了验证上述遍历函数的正确性,我们可以创建一个简单的二叉树并调用这些函数:

int main() {
    // 创建一个简单的二叉树
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->left->left = new TreeNode(4);
    root->left->right = new TreeNode(5);

    // 递归遍历
    cout << "递归前序遍历: ";
    preOrderRecursive(root);
    cout << endl;

    cout << "递归中序遍历: ";
    inOrderRecursive(root);
    cout << endl;

    cout << "递归后序遍历: ";
    postOrderRecursive(root);
    cout << endl;

    // 非递归遍历
    cout << "非递归前序遍历: ";
    preOrderNonRecursive(root);
    cout << endl;

    cout << "非递归中序遍历: ";
    inOrderNonRecursive(root);
    cout << endl;

    cout << "非递归后序遍历: ";
    postOrderNonRecursive(root);
    cout << endl;

    return 0;
}

结语

递归和非递归遍历是二叉树操作中的基础技能。递归方法简洁易懂,但可能会遇到栈溢出的问题;非递归方法虽然代码复杂一些,但可以避免递归带来的问题。理解这两种方法的原理和实现,对于深入学习数据结构和算法非常有帮助。

希望这篇文章能帮助你更好地理解二叉树的遍历方法。如果你有任何问题或建议,请在评论区告诉我。感谢阅读!

标签:遍历,TreeNode,递归,C++,current,二叉树,left
From: https://blog.csdn.net/weixin_72391681/article/details/141269132

相关文章

  • 【CPP】C++模板:初阶到进阶语法与实用编程示例
    关于我:睡觉待开机:个人主页个人专栏:《优选算法》《C语言》《CPP》生活的理想,就是为了理想的生活!作者留言PDF版免费提供:倘若有需要,想拿我写的博客进行学习和交流,可以私信我将免费提供PDF版。留下你的建议:倘若你发现本文中的内容和配图有任何错误或改进建......
  • C++ 小节3
    1、析构函数相关1.析构函数:函数名与类名相同,前面有~,没有返回值,不能写void,没有参数;只能有一个,不能重载2.析构函数的作用:主要在对象销毁时释放申请的堆内存,关闭文件,关闭网络连接,关闭数据库连接等;3.析构函数的执行:(不显式调用,自动执行)1)作用域到了时自动执行析构函数......
  • C/C++内存管理
    文章目录前言C/C++内存分布C语言内存管理malloccallocreallocreallocarrayfreeC++内存管理new/delete内置类型自定义类型operatornew/operatordelete定位new内存泄漏前言        C++的内存管理是程序设计中的一个关键部分,涉及到内存的分配、使用和释......
  • 数据结构(C++版)——顺序表
    一、顺序表有关的基本操作1、InitList(&L):初始化线性表,构造一个空的线性表L2、DestroyList(&L):销毁线性表L3、ClearList(&L):将线性表L重置为空表4、ListEmpty(L):若L为空表,则返回TURE,否则返回FALSE5、GetElem(L,i,&e):用e返回L中第i个数据元素的值6、LocateElem(L,e):在线性......
  • C++八股文——内存管理(堆和栈的区别? C++内存分区? 内存泄漏?如何避免?什么是智能指针?有哪
    文章目录C++内存管理堆和栈的区别C++内存分区内存泄漏?如何避免?1、什么是内存泄露?2、内存泄漏的分类3、什么操作会导致内存泄露?4、如何防⽌内存泄露?5、智能指针有了解哪些?6、构造函数,析构函数要设为虚函数吗,为什么?什么是智能指针?有哪些种类?new和malloc有什么区别?d......
  • 函数递归VS操作符深入?
    1>>前言    函数递归函数递归,当小白听到这样的词会感到无比陌生,请不要惊慌,这是正常的,以至于都不是很经常用到,但是它的算法,它的思想是值得我们深入思考的。还有一些复杂操作符,如按位与按位或等等,今天一并说说,希望大家能学到东西。2>>函数递归    函数的递归......
  • C++智能指针讨论
    一段有问题的代码。#include<iostream>intmain(){for(inti=0;i<10000000;i++){double*p=newdouble(1);}return0;}这里就有了内存泄漏。修改为下边的代码,是可以的,但是会比较占用CPU资源。#include<iostream>intmain()......
  • C++速览之智能指针
    1、存在的问题c++把内存的控制权对程序员开放,让程序显式的控制内存,这样能够快速的定位到占用的内存,完成释放的工作。但是此举经常会引发一些问题,比如忘记释放内存。由于内存没有得到及时的回收、重复利用,所以在一些c++程序中,常会遇到程序突然退出、占用内存越来越多,最后不......
  • C++ Debug
    如果右上角没有runanddebugbutton记得把setting里IntelliSenseEngine改成default,以及DebugShortcut打开如果cpp文件提示headernotfound,那需要在c_cpp_properties.json中把compilerPath,添加上debug的时候,默认他好像是会自动build的,当然也可以自己写p......
  • C++构造和析构
    文章目录一、构造函数1、构造函数的功能2、构造函数的创建3、默认构造函数二、析构函数1、析构函数的功能2、析构函数的的创建三、拷贝构造函数1、拷贝构造的功能2、拷贝构造的创建3、深拷贝一、构造函数1、构造函数的功能构造函数是一个类的成员函数,在类创......