【二叉树】风格统一,简单易记的二叉树非递归遍历

本文提出一种统一的非递归方法实现二叉树的前序、中序和后序遍历,通过引入标记来区分节点状态,使得不同遍历方式的代码风格一致且易于理解。

二叉树递归遍历的缺点很多,函数跳转拖慢速度,二叉树深度大时还会导致爆栈。相较之下非递归遍历就没有这些问题,但网络上的三种非递归遍历代码并没有做到递归代码那种程度的风格统一,易于理解(同一个人写的三种非递归遍历之间变量数、判断体中的语句数均各有不同,而递归遍历之间只是访问节点的位置不同,其他部分可以完全一致),因此我决定做一个简单归纳,让非递归代码也能像递归代码那样风格统一,便于记忆。


注意:我的算法与网络上大部分算法相比付出了额外的空间,请读者自行取舍。

原题地址

前序 中序 后序

代码

class Solution {
public:
    typedef TreeNode *np;
    typedef pair<np,bool> mark;
    //前序遍历
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        if(!root){
            return result;
        }
        stack<pair<np,bool>> data;
        data.push(mark(root,false));
        while(!data.empty()){
            if(!data.top().second){
                np temp = data.top().first;
                data.pop();
                if(temp->right){
                    data.push(mark(temp->right,false));
                }
                if(temp->left){
                    data.push(mark(temp->left,false));
                }
                data.push(mark(temp,true));//注意这行的位置变化
            }else{
                result.push_back(data.top().first->val);
                data.pop();
            }
        }
        return result;
    }
    //中序遍历
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        if(!root){
            return result;
        }
        stack<pair<np,bool>> data;
        data.push(mark(root,false));
        while(!data.empty()){
            if(!data.top().second){
                np temp = data.top().first;
                data.pop();
                if(temp->right){
                    data.push(mark(temp->right,false));
                }
                data.push(mark(temp,true));//注意这行的位置变化
                if(temp->left){
                    data.push(mark(temp->left,false));
                }
            }else{
                result.push_back(data.top().first->val);
                data.pop();
            }
        }
        return result;
    }
    //后序遍历
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        if(!root){
            return result;
        }
        stack<pair<np,bool>> data;
        data.push(mark(root,false));
        while(!data.empty()){
            if(!data.top().second){
                np temp = data.top().first;
                data.pop();
                data.push(mark(temp,true));//注意这行的位置变化
                if(temp->right){
                    data.push(mark(temp->right,false));
                }
                if(temp->left){
                    data.push(mark(temp->left,false));
                }
            }else{
                result.push_back(data.top().first->val);
                data.pop();
            }
        }
        return result;
    }
};

mark.second记录了这个节点有没有被访问过,有了这条信息就可以很方便的写出风格统一的代码。

1.将mark(root,false)入栈
2.从原理上栈中节点指针不可能为NULL,因此程序必须事先判断root是否为NULL。
3.如果栈顶节点未访问过,则将其按各自的规律展开:
前序:栈顶……原节点……栈底 => 栈顶…… 原节点、左孩子、右孩子……栈底
中序:栈顶……原节点……栈底 => 栈顶…… 左孩子、原节点、右孩子……栈底
后序:栈顶……原节点……栈底 => 栈顶…… 左孩子、右孩子、原节点……栈底
展开时,如果left或right为NULL,则不压入任何东西
如果栈顶节点已经访问过一次,则将val记录后出栈
4.重复上一步直到栈为空

当然,代码中有几处是可以简化的,为了保持整齐我就没有进行省略。
如果可以在保持整齐的前提下进行优化(主要是空间上),欢迎评论指出

<think>好的,我现在需要帮用户找到用C语言实现二叉树的创建和遍历的代码示例。用户提到了他们已有的三个引用,分别是前序、中序遍历以及创建的代码。首先,我应该综合这些引用,生成一个完整的创建和遍历的示例。 首先看引用[2],里面有一个CreateTree函数,通过读取文件中的字符来构建二叉树。使用'#'表示空节点,这应该是一个常见的做法。不过用户可能需要一个更直观的创建方法,比如手动构建节点,如引用[1]中的示例。所以在示例代码中,可能需要结合这两种方法,或者提供一个手动构建的例子,因为从文件读取可能对用户来说不够直观。 然后,遍历部分,引用[1]提供了前序遍历的递归实现,引用[3]是中序遍历。用户需要的是创建与遍历的完整示例,所以需要包括前序、中序、后序遍历三种方式,可能还有层次遍历,但用户引用中没有层次遍历的代码,可能需要补充。不过根据用户提供的引用,可能只需要展示递归方式的三种遍历。 接下来,结构体定义部分,引用[1]中的结构体是typedef struct BiTNode,包含data、lchild和rchild。需要确保结构体定义正确,并在创建节点正确分配内存。 用户可能需要一个完整的可编译的代码示例,包括main函数中的初始化二叉树的部分。比如引用[1]中的main函数初始化了一个具体的二叉树结构,并调用前序遍历函数。但用户可能需要更完整的创建过程,比如通过CreateTree函数从输入构建,或者手动连接节点。 可能需要注意内存分配是否正确,比如malloc之后是否检查了返回值,但通常在示例代码中可能会省略错误检查,以保持简洁。 另外,用户提供的引用中有不同的函数实现方式,需要统一风格,比如函数名和参数的一致性。例如,引用[1]中的PreOrderTraversal使用BiTree类型,而引用[3]中的BTreeInOrder使用struct TreeNode*。需要统一为相同的结构体类型。 还需要考虑注释和代码的可读性,确保用户能够理解每个步骤的作用。比如在创建二叉树,手动连接各个节点,或者在遍历函数中添加注释说明访问顺序。 最后,生成相关问题,可能涉及遍历的应用、不同遍历方式的区别、非递归实现方法等,但要根据用户提供的引用来生成,比如递归实现的优化、创建函数的具体使用等。 综合以上分析,我需要编写一个包含结构体定义、手动创建二叉树、三种递归遍历的示例代码,并确保代码语法正确,符合用户提供的引用中的方法。同,添加适当的注释,并在最后生成相关问题。</think>以下是用C语言实现二叉树创建与遍历的完整示例代码,包含前序、中序、后序遍历实现: ```c #include <stdio.h> #include <stdlib.h> // 定义二叉树节点结构体 typedef struct BiTNode { char data; // 节点数据(char类型示例) struct BiTNode *lchild; // 左子树指针 struct BiTNode *rchild; // 右子树指针 } BiTNode, *BiTree; // 手动创建二叉树函数 BiTree CreateBinaryTree() { BiTree root = (BiTNode*)malloc(sizeof(BiTNode)); root->data = 'A'; root->lchild = (BiTNode*)malloc(sizeof(BiTNode)); root->lchild->data = 'B'; root->rchild = (BiTNode*)malloc(sizeof(BiTNode)); root->rchild->data = 'C'; root->lchild->lchild = (BiTNode*)malloc(sizeof(BiTNode)); root->lchild->lchild->data = 'D'; root->lchild->lchild->lchild = NULL; root->lchild->lchild->rchild = NULL; root->lchild->rchild = (BiTNode*)malloc(sizeof(BiTNode)); root->lchild->rchild->data = 'E'; root->lchild->rchild->lchild = NULL; root->lchild->rchild->rchild = NULL; root->rchild->rchild = (BiTNode*)malloc(sizeof(BiTNode)); root->rchild->rchild->data = 'F'; root->rchild->rchild->lchild = NULL; root->rchild->rchild->rchild = NULL; return root; } // 前序遍历(根左右) void PreOrderTraversal(BiTree root) { if (root != NULL) { printf("%c ", root->data); // 访问根节点 PreOrderTraversal(root->lchild); // 遍历左子树 PreOrderTraversal(root->rchild); // 遍历右子树 } } // 中序遍历(左根右) void InOrderTraversal(BiTree root) { if (root != NULL) { InOrderTraversal(root->lchild); // 遍历左子树 printf("%c ", root->data); // 访问根节点 InOrderTraversal(root->rchild); // 遍历右子树 } } // 后序遍历(左右根) void PostOrderTraversal(BiTree root) { if (root != NULL) { PostOrderTraversal(root->lchild); // 遍历左子树 PostOrderTraversal(root->rchild); // 遍历右子树 printf("%c ", root->data); // 访问根节点 } } int main() { BiTree root = CreateBinaryTree(); printf("前序遍历结果:"); PreOrderTraversal(root); // 输出:A B D E C F printf("\n中序遍历结果:"); InOrderTraversal(root); // 输出:D B E A C F printf("\n后序遍历结果:"); PostOrderTraversal(root); // 输出:D E B F C A return 0; } ``` 该代码实现了: 1. 通过$struct\ BiTNode$定义二叉树节点结构[^1] 2. 使用$CreateBinaryTree()$手动构建示例二叉树 3. 包含前序/中序/后序三种递归遍历实现 4. 内存动态分配使用$malloc$函数 5. 节点使用字符型数据简化示例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值