当前位置: 首页 > news >正文

数据结构实验报告-树与二叉树

     

一、实验名称:

实验6 树和二叉树

二、实验内容:

1.编写二叉树的递归遍历算法,实现:给定一棵二叉树的“扩展先序遍历序列”,创建这棵二叉树。

(1)输出二叉树的先序遍历的结点序列。

(2)输出二叉树的后序遍历的结点序列。

(3)输出二叉树的中序遍历的结点序列。

(4)输出二叉树的叶子结点。

(5)统计二叉树的结点个数。

源码:
#include <stdio.h>

#include <stdlib.h>

typedef struct TreeNode {

    char data;

    struct TreeNode *left;

    struct TreeNode *right;

} TreeNode;

// 创建二叉树

TreeNode* createBinaryTree(char *str, int *index) {

    if (str[*index] == '\0') {

        return NULL;

    }

    if (str[*index] == '#') {

        (*index)++;

        return NULL;

    }

    TreeNode *root = (TreeNode*)malloc(sizeof(TreeNode));

    root->data = str[*index];

    (*index)++;

   

    root->left = createBinaryTree(str, index);

    root->right = createBinaryTree(str, index);

    return root;

}

// 先序遍历

void preorder(TreeNode *root) {

    if (root != NULL) {

        printf("%c ", root->data);

        preorder(root->left);

        preorder(root->right);

    }

}

// 后序遍历

void postorder(TreeNode *root) {

    if (root != NULL) {

        postorder(root->left);

        postorder(root->right);

        printf("%c ", root->data);

    }

}

// 中序遍历

void inorder(TreeNode *root) {

    if (root != NULL) {

        inorder(root->left);

        printf("%c ", root->data);

        inorder(root->right);

    }

}

// 输出叶子节点

void printLeaves(TreeNode *root) {

    if (root != NULL) {

        if (root->left == NULL && root->right == NULL) {

            printf("%c ", root->data);

        }

        printLeaves(root->left);

        printLeaves(root->right);

    }

}

// 统计节点个数

int countNodes(TreeNode *root) {

    if (root == NULL) {

        return 0;

    }

    return 1 + countNodes(root->left) + countNodes(root->right);

}

int main() {

    char str[] = "AB#D##CE##"; // 示例扩展先序遍历序列

    int index = 0;

    TreeNode *root = createBinaryTree(str, &index);

    printf("先序遍历序列: ");

    preorder(root);

    printf("\n");

    printf("后序遍历序列: ");

    postorder(root);

    printf("\n");

    printf("中序遍历序列: ");

    inorder(root);

    printf("\n");

    printf("叶子节点: ");

    printLeaves(root);

    printf("\n");

    printf("节点个数: %d\n", countNodes(root));

    return 0;

}

2.编写非递归遍历算法,实现:给定一棵二又树的先序 遍历序列和中序通历序列,创建这棵二叉树。

(1)输出二叉树的后序遍历的结点序列。

(2)输出二叉树的叶子结点。

(3)统计二叉树的结点个数。

(4)求二叉树的深度。

(5)输出二叉树指定结点的路径。

源码:
#include <iostream>

#include <stack>

#include <vector>

#include <unordered_map>

using namespace std;

struct TreeNode {

    char data;

    TreeNode* left;

    TreeNode* right;

    TreeNode(char val) : data(val), left(NULL), right(NULL) {}

};

TreeNode* buildTree(vector<char>& preorder, vector<char>& inorder) {

    if (preorder.empty() || inorder.empty()) return NULL;

    unordered_map<char, int> inorder_map;

    for (int i = 0; i < inorder.size(); ++i) {

        inorder_map[inorder[i]] = i;

    }

    stack<TreeNode*> stk;

    TreeNode* root = new TreeNode(preorder[0]);

    stk.push(root);

    for (int i = 1; i < preorder.size(); ++i) {

        TreeNode* node = new TreeNode(preorder[i]);

        TreeNode* top = stk.top();

        if (inorder_map[node->data] < inorder_map[top->data]) {

            top->left = node;

        } else {

            TreeNode* parent = NULL;

            while (!stk.empty() && inorder_map[node->data] > inorder_map[stk.top()->data]) {

                parent = stk.top();

                stk.pop();

            }

            parent->right = node;

        }

        stk.push(node);

    }

    return root;

}

void postorderTraversal(TreeNode* root) {

    if (root == NULL) return;

   

    stack<TreeNode*> stk;

    vector<char> result;

    stk.push(root);

    while (!stk.empty()) {

        TreeNode* node = stk.top();

        stk.pop();

        result.insert(result.begin(), node->data);

        if (node->left) stk.push(node->left);

        if (node->right) stk.push(node->right);

    }

    for (char ch : result) {

        cout << ch << " ";

    }

}

void printLeaves(TreeNode* root) {

    if (root == NULL) return;

    if (root->left == NULL && root->right == NULL) {

        cout << root->data << " ";

    }

    printLeaves(root->left);

    printLeaves(root->right);

}

int countNodes(TreeNode* root) {

    if (root == NULL) return 0;

    return 1 + countNodes(root->left) + countNodes(root->right);

}

int maxDepth(TreeNode* root) {

    if (root == NULL) return 0;

    return 1 + max(maxDepth(root->left), maxDepth(root->right));

}

void findPath(TreeNode* root, char target, vector<char>& path) {

    if (root == NULL) return;

    path.push_back(root->data);

    if (root->data == target) {

        for (char ch : path) {

            cout << ch << " ";

        }

        cout << endl;

    }

    findPath(root->left, target, path);

    findPath(root->right, target, path);

    path.pop_back();

}

int main() {

    vector<char> preorder = {'A', 'B', 'D', 'E', 'C', 'F', 'G'};

    vector<char> inorder = {'D', 'B', 'E', 'A', 'F', 'C', 'G'};

    TreeNode* root = buildTree(preorder, inorder);

    cout << "后序遍历序列: ";

    postorderTraversal(root);

    cout << endl;

    cout << "叶子节点: ";

    printLeaves(root);

    cout << endl;

    cout << "节点个数: " << countNodes(root) << endl;

    cout << "二叉树深度: " << maxDepth(root) << endl;

    char target = 'D';

    cout << "路径(" << target << "): ";

    vector<char> path;

    findPath(root, target, path);

    return 0;

}

3.1题,编写算法实现二叉树的先序线索化,并查找结点p的先序前驱结点和先序后继结点。

源码:
#include <iostream>

#include <stack>

using namespace std;

struct TreeNode {

    char data;

    TreeNode *left;

    TreeNode *right;

    bool isThreaded; // 线索化标记

    TreeNode(char val) : data(val), left(NULL), right(NULL), isThreaded(false) {}

};

void preorderThreading(TreeNode* root, TreeNode*& prev) {

    if (root == NULL) return;

    if (root->left == NULL) {

        root->left = prev;

        root->isThreaded = true;

    }

    if (prev != NULL && prev->right == NULL) {

        prev->right = root;

        prev->isThreaded = true;

    }

    prev = root;

    if (!root->isThreaded) {

        preorderThreading(root->left, prev);

    }

    preorderThreading(root->right, prev);

}

TreeNode* preorderSuccessor(TreeNode* node) {

    if (node->isThreaded) {

        return node->right;

    } else {

        TreeNode* curr = node->right;

        while (curr != NULL && !curr->isThreaded) {

            curr = curr->left;

        }

        return curr;

    }

}

TreeNode* preorderPredecessor(TreeNode* node) {

    if (node->left != NULL) {

        TreeNode* curr = node->left;

        while (curr->right != NULL && !curr->right->isThreaded) {

            curr = curr->right;

        }

        return curr;

    } else {

        return node->right;

    }

}

int main() {

    TreeNode *root = new TreeNode('A');

    root->left = new TreeNode('B');

    root->right = new TreeNode('C');

    root->left->left = new TreeNode('D');

    root->left->right = new TreeNode('E');

    root->right->left = new TreeNode('F');

    root->right->right = new TreeNode('G');

    TreeNode *prev = NULL;

    preorderThreading(root, prev);

    TreeNode *target = root->left; // 以结点'B'为例

    TreeNode *predecessor = preorderPredecessor(target);

    TreeNode *successor = preorderSuccessor(target);

    if (predecessor) {

        cout << "结点'" << target->data << "'的先序前驱结点是: " << predecessor->data << endl;

    } else {

        cout << "结点'" << target->data << "'没有先序前驱结点" << endl;

    }

    if (successor) {

        cout << "结点'" << target->data << "'的先序后继结点是: " << successor->data << endl;

    } else {

        cout << "结点'" << target->data << "'没有先序后继结点" << endl;

    }

    return 0;

}

四、心得体会:

通过实现二叉树的先序线索化算法,并查找指定结点的先序前驱和后继结点,我深刻体会到了树结构的复杂和线索化的重要性。在操作过程中,我学会了如何处理线索化和利用前序遍历进行结点的查找,进一步加深了对二叉树数据结构的理解。通过这一实践,我意识到了算法设计的精妙之处,同时也深感数据结构对于解决复杂问题的重要性。在编写代码的过程中,我不断思考优化方案,增强了自己的编程能力和逻辑思维能力。总的来说,这次实践让我收获颇丰,同时也更加坚定了我对算法与数据结构学习的重要性,激发了我对计算机科学领域的无限热情。

相关文章:

数据结构实验报告-树与二叉树

桂 林 理 工 大 学 实 验 报 告 一、实验名称&#xff1a; 实验6 树和二叉树 二、实验内容&#xff1a; 1.编写二叉树的递归遍历算法&#xff0c;实现:给定一棵二叉树的“扩展先序遍历序列”&#xff0c;创建这棵二叉树。 (1)输出二叉树的先序遍历的结点序列。 (2)输出二…...

基于Django+MySQL球馆场地预约系统的设计与实现(源码+论文+部署讲解等)

博主介绍&#xff1a;✌全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术栈介绍&#xff1a;我是程序员阿龙&#xff…...

8 MQTT

8 MQTT 1、相关概念2、MQTT的操作过程3、MQTT协议3.1 固定报文3.2 连接报文3.3 确认连接请求3.4 构造订阅报文3.5 订阅确认报文3.6 发布报文3.7 其他报文 1、相关概念 MQTT [1] 全名为Message Queuing Telemetry Transport&#xff0c;是一种基于TCP/IP协议上传输的轻量级通信…...

【文件系统】抽象磁盘的存储结构 CHS寻址法 | sector数组 | LAB数组

目录 1.为什么要抽象 2.逻辑抽象_版本1 2.1sector数组 ​2.2index转化CHS 3.逻辑抽象_版本2 3.1LBA数组 3.2LAB下标转化sector下标 文件其实就是在磁盘中占有几个扇区的问题❗文件是很多个sector的数组下标❗文件是有很多块构成的❗❗文件由很多扇区构成------>文件…...

基于python旅游推荐系统(源码+论文+部署讲解等)

博主介绍&#xff1a;✌全网粉丝10W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术栈介绍&#xff1a;我是程序员阿龙&#xff…...

Mysql大单表JSON优化

优化方案 MySQL 8.0.32 中&#xff0c;有几种方法可以优化存储 JSON 字符串的数据表。以下是一些建议&#xff0c;可以帮助您减少存储空间&#xff1a; 使用压缩: MySQL 8.0 支持表级压缩&#xff0c;可以通过修改表来启用压缩。 ALTER TABLE your_table ROW_FORMATCOMPRESS…...

电脑开机启动项管理小工具,绿色免安装

HiBit Startup Manager 是一款功能强大的启动项管理工具&#xff0c;旨在帮助用户管理和优化计算机的自动启动程序。该软件通过添加或删除应用程序、编辑它们的属性以及管理流程、服务、任务调度程序和上下文菜单来实现这一目标。 HiBit Startup Manager 提供了以下主要功能&a…...

一例AutoHotkey语言生成的文件夹病毒分析

概述 这是一个使用AutoHotkey语言编写的文件夹病毒&#xff0c;使用ftp服务器来当作C2&#xff0c;通过U盘传播&#xff0c;样本很古老&#xff0c;原理也很简单&#xff0c;这种语言的样本还是第一次见到&#xff0c;记录一下。 样本的基本信息 PE32库: AutoIt(3.XX)[-]编译…...

【机器学习第7章——贝叶斯分类器】

机器学习第7章——贝叶斯分类器 7.贝叶斯分类器7.1贝叶斯决策论7.2 朴素贝叶斯分类器条件概率的m估计 7.3 极大似然估计优点基本原理 7.4 贝叶斯网络7.5 半朴素贝叶斯分类器7.6 EM算法7.7 EM算法实现 7.贝叶斯分类器 7.1贝叶斯决策论 一个医疗判断问题 有两个可选的假设&#…...

C++ QT开发 学习笔记(3)

C QT开发 学习笔记(3) - WPS项目 标准对话框 对话框类说明静态函数函数说明QFileDialog文件对话框getOpenFileName()选择打开一个文件getOpenFileNames()选择打开多个文件getSaveFileName()选择保存一个文件getExistingDirectory()选择一个己有的目录getOpenFileUrl()选择打幵…...

【Python实战】如何优雅地实现文字 二维码检测?

前几篇&#xff0c;和大家分享了如何通过 Python 和相关库&#xff0c;自动化处理 PDF 文档&#xff0c;提高办公效率。 【Python实战】自动化处理 PDF 文档&#xff0c;完美实现 WPS 会员功能【Python实战】如何优雅地实现 PDF 去水印&#xff1f;【Python实战】一键生成 PDF…...

行为型设计模式3:模板方法/备忘录/解释器/迭代器

设计模式&#xff1a;模板方法/备忘录/解释器/迭代器 (qq.com)...

思源笔记软件的优缺点分析

在过去一年里&#xff0c;我用了很多款笔记&#xff0c;从word文档到onenote到语雀再到思源&#xff0c;最后坚定的选择了思源笔记 使用感受 首先是用word文档来记笔记&#xff0c;主要是开始时不知道笔记软件怎么好用&#xff0c;等到笔记越来越膨胀的时候我发现&#xff0c…...

追问试面试系列:Dubbo

欢迎来到Dubbo系列,在面试中被问到Dubbo相关的问题时,大部分都是简历上写了Dubbo,或者面试官想尝试问问你对Dubbo是否了解。 本系列主要是针对面试官通过一个点就使劲儿往下问的情况。 面试官:说说你们项目亮点 好的面试官 我们这个项目的技术亮点在于采用了Spring Cloud…...

动手学深度学习V2每日笔记(卷积层)

本文主要参考沐神的视频教程 https://www.bilibili.com/video/BV1L64y1m7Nh/p2&spm_id_from333.1007.top_right_bar_window_history.content.click&vd_sourcec7bfc6ce0ea0cbe43aa288ba2713e56d 文档教程 https://zh-v2.d2l.ai/ 本文的主要内容对沐神提供的代码中个人不…...

qcom ucsi probe

ucsi glink 注册一个ucsi 设备&#xff0c;和pmic glink进行通信&#xff0c;ucsi作为pmic glink的一个client。 lkml的patch https://lkml.org/lkml/2023/1/30/233 dtsi中一般会定义 qcom,ucsi-glink 信息&#xff0c;用于和驱动进行匹配 static const struct of_device_id …...

flask和redis配合

对于涉及数据提交的场景&#xff0c;比如更新用户信息&#xff0c;你可能会使用POST或PUT请求。但是&#xff0c;这些操作通常与直接从Redis缓存中检索数据不同&#xff0c;因为它们可能涉及到对后端数据库或其他存储系统的修改。并且可能需要将更新后的数据同步回Redis缓存&am…...

深度学习中的早停法

早停法&#xff08;Early Stopping&#xff09;是一种用于防止模型过拟合的技术&#xff0c;在训练过程中监视验证集&#xff08;或者测试集&#xff09;上的损失值。具体设立早停的限制包括两个主要参数&#xff1a; Patience&#xff08;耐心&#xff09;&#xff1a;这是指验…...

科普文:JUC系列之多线程门闩同步器CountDownLatch的使用和源码

CountDownLatch类位于java.util.concurrent包下&#xff0c;利用它可以实现类似计数器的功能。比如有一个任务A&#xff0c;它要等待其他10个线程的任务执行完毕之后才能执行&#xff0c;此时就可以利用CountDownLatch来实现这种功能了。 CountDownLatch是通过一个计数器来实现…...

foreach循环和for循环在PHP中各有什么优势

在PHP中&#xff0c;foreach循环和for循环都是用来遍历数组的常用结构&#xff0c;但它们各有其优势和使用场景。 foreach循环的优势 简化代码&#xff1a;foreach循环提供了一种更简洁的方式来遍历数组&#xff0c;不需要手动控制索引或指针。易于阅读&#xff1a;对于简单的…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

HBuilderX安装(uni-app和小程序开发)

下载HBuilderX 访问官方网站&#xff1a;https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本&#xff1a; Windows版&#xff08;推荐下载标准版&#xff09; Windows系统安装步骤 运行安装程序&#xff1a; 双击下载的.exe安装文件 如果出现安全提示&…...

AI编程--插件对比分析:CodeRider、GitHub Copilot及其他

AI编程插件对比分析&#xff1a;CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展&#xff0c;AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者&#xff0c;分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

【JVM面试篇】高频八股汇总——类加载和类加载器

目录 1. 讲一下类加载过程&#xff1f; 2. Java创建对象的过程&#xff1f; 3. 对象的生命周期&#xff1f; 4. 类加载器有哪些&#xff1f; 5. 双亲委派模型的作用&#xff08;好处&#xff09;&#xff1f; 6. 讲一下类的加载和双亲委派原则&#xff1f; 7. 双亲委派模…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

TCP/IP 网络编程 | 服务端 客户端的封装

设计模式 文章目录 设计模式一、socket.h 接口&#xff08;interface&#xff09;二、socket.cpp 实现&#xff08;implementation&#xff09;三、server.cpp 使用封装&#xff08;main 函数&#xff09;四、client.cpp 使用封装&#xff08;main 函数&#xff09;五、退出方法…...

拟合问题处理

在机器学习中&#xff0c;核心任务通常围绕模型训练和性能提升展开&#xff0c;但你提到的 “优化训练数据解决过拟合” 和 “提升泛化性能解决欠拟合” 需要结合更准确的概念进行梳理。以下是对机器学习核心任务的系统复习和修正&#xff1a; 一、机器学习的核心任务框架 机…...