数据结构与算法实验报告 二

实验二    二叉树的基本操作

一、实验目的

本实验通过实现二叉树的链式存储实现及二叉树的基本操作,掌握递归算法的

设计、递归算法与非递归算法之间的转换和遍历技术,为后续章节学习图的内容奠

定基础。

二、实验内容

(1)、以链表为存储结构创建二叉树;

(2)、分别用递归和非递归方式实现二叉树的中序遍历;

三、实验原理、方法和手段

链表存储二叉树通常具有两个指针域的链表作为二叉树的存储结构,其中每个

结点由数据域、左指针域和右指针域组成。两个指针域分别指向该结点的左、右孩

子。若某结点没有左孩子或右孩子,则对应的指针域为空。最后,还需要一个链表

的头指针指向根结点。

二叉树是非线性结构,遍历时先访问根结点还是先访问子树、先访问左子树还

是先访问右子树必须有所规定,这就是遍历规则。采用不同的遍历规则会产生不同

的遍历结果,因此对二叉树进行遍历时,必须设定遍历规则。根据遍历规则采用递

归或者非递归的方式实现二叉树的遍历。采用非递归算法实现中序遍历时要用到栈

结构。根据中序遍历二叉树的递归定义,转换成非递归函数时用栈来保存返回的结

点,先扫描根结点的所有左结点并入栈,出栈一个结点,访问之,然后扫描该结点

的右结点并入栈再扫描该右结点的所有左结点并入栈,如此下去……,直到到栈空

为止。

代码如下
#include <iostream>
#include <stack>

using namespace std;

class TreeNode {
public:
    int value;
    TreeNode* left, * right;

    TreeNode(int value) {
        this->value = value;
        left = right = nullptr;
    }
};

TreeNode* createBinaryTree() {
    // 创建一个简单的二叉树(硬编码)
    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);

    return root;
}

// 注释处为递归遍历算法
/*void inorderTraversalRecursive(TreeNode* node) {
    if (node == nullptr) return;
    inorderTraversalRecursive(node->left);
    cout << node->value << " ";
    inorderTraversalRecursive(node->right);
}*/


void inorderTraversalIterative(TreeNode* root) {
    stack<TreeNode*> stk;
    TreeNode* current = root;

    while (current != nullptr || !stk.empty()) {
        while (current != nullptr) {
            stk.push(current);
            current = current->left;
        }

        current = stk.top();
        stk.pop();
        cout << current->value << " ";
        current = current->right;
    }
}

int main() {
    TreeNode* root = createBinaryTree();

    // 注释处为递归遍历算法
    /*      cout << "Inorder Traversal (Recursive): ";
    inorderTraversalRecursive(root);
    cout << endl;*/

    cout << "Inorder Traversal (Iterative): ";
    inorderTraversalIterative(root);
    cout << endl;

    return 0;
}

结果:

实验结果分析

在实验中,我们实现了二叉树的中序遍历的两种方法:递归和非递归(利用栈)。这两种方法虽然在实现细节上有所不同,但它们都按照左子树-根节点-右子树的顺序访问树中的每个节点。

1. 递归方法:

   优点:代码简洁易懂,直观地反映了中序遍历的定义。

   缺点:对于深度很大的树,可能会导致调用栈溢出。

2. 非递归方法(使用栈):

   优点:避免了递归可能导致的栈溢出问题,适用于深度较大的树。

   缺点:代码相对复杂,需要额外的数据结构(栈)来存储访问路径。

对于给定的二叉树,两种方法都能正确地输出中序遍历的结果(4 2 5 1 3),这验证了方法的正确性。

思考题

如何实现层次遍历?

#include <queue>

void levelOrderTraversal(TreeNode* root) {
    if (root == nullptr) return;

    queue<TreeNode*> q;
    q.push(root);

    while (!q.empty()) {
        TreeNode* current = q.front();
        q.pop();
        cout << current->value << " ";

        if (current->left != nullptr) {
            q.push(current->left);
        }
        if (current->right != nullptr) {
            q.push(current->right);
        }
    }
}
  1. levelOrderTraversal() 函数接受一个指向树根节点的指针作为参数,用于层序遍历二叉树。

  2. 首先,检查树是否为空,如果为空则直接返回。

  3. 创建一个队列 q,并将根节点入队。

  4. 进入循环,直到队列为空。在每一轮循环中:

    • 出队队首元素,将当前节点的值输出。
    • 如果当前节点的左子节点不为空,将左子节点入队。
    • 如果当前节点的右子节点不为空,将右子节点入队。
  5. 循环直到队列为空,此时完成了层序遍历。

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值