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

数据结构:树详解

创建二叉树

给出了完整的先序遍历序列,子树为空用’#’表示,所以这样我们在通过先序遍历序列创建二叉树时我们直到先序遍历序列是先进行根结点,然后左子树最后右子树的顺序进行遍历的,所以对于完整的先序遍历序列我们可以直到先序遍历序列中第一个元素是二叉树的根结点,如果第二个元素不为’#’,那么这个代表二叉树有左孩子,而且左孩子的值为先序遍历序列的第二个元素的值,依次类推,根据二叉树的完整先序遍历序列我们可以直到每一个结点是否为空,这样我们就能够采取递归形式进行二叉树的创建:
创建过程的图示为如下:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

最终我们得到的树如下图所示:
在这里插入图片描述

有了上面的思路我们可以写出如下代码:

void InitBinaryTree(char *p, int *length, struct BinaryTreeNode **root){if(p[*length]!=0){if(p[*length]!='#'){*root = (struct BinaryTreeNode *)malloc(sizeof(struct BinaryTreeNode));(*root)->val = p[*length];(*root)->left = NULL;(*root)->right = NULL;(*length)++;InitBinaryTree(p, length, &(*root)->left);InitBinaryTree(p, length, &(*root)->right);	}else{(*length)++;}}
}

这就是通过树的完整前序遍历序列创建二叉树的过程。
下面我们来进行实现二叉树的前序遍历、中序遍历与后序遍历,前序遍历是指先根结点再左子树最后右子树,中序遍历是先左子树然后根结点最后右子树,后序遍历是先左子树然后右子树最后根结点,这种遍历可以通过递归进行实现,在每次递归中所在结点不为NULL就说明结点有值,我们需要遍历这一个结点的左子树与右子树,也就是递归截至的条件是root==NULL;有了这样的思路前序遍历与中序遍历,与后序遍历就只是根结点的访问顺序发生改变,我们可以写出下面的三种遍历的代码:
前序遍历:

//本函数实现二叉树的前序遍历功能
void preOrderTraversal(struct BinaryTreeNode *root){if(root!=NULL){printf("%c ", root->val);preOrderTraversal(root->left);preOrderTraversal(root->right);	}
}

中序遍历:

//本函数实现二叉树的中序遍历功能
void inOrderTraversal(struct BinaryTreeNode *root){if(root!=NULL){inOrderTraversal(root->left);printf("%c ", root->val);inOrderTraversal(root->right);	}
}

后序遍历:

// 本函数实现二叉树的后序遍历功能
void postOrderTraversal(struct BinaryTreeNode *root){if(root!=NULL){postOrderTraversal(root->left);postOrderTraversal(root->right);printf("%c ", root->val);	}
}

就以上面的建立的二叉树为例查看一下该二叉树的前序遍历序列、中序遍历序列、后序遍历序列。
二叉树的前序遍历序列应为:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

中序遍历序列应为:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

后序遍历序列应为:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

我们来运行一下看看结果是否正确:
在这里插入图片描述
可以看出结果确实正确。
至此关于二叉树的内容已经全部实现,接下来实现哈夫曼树以及编码操作,题目中给出了’a’ ‘b’ ‘c’ ‘d’以及其对应出现的次数分别是7、5、2、4,出现次数多的字母编码要尽可能的短,我们可以利用哈夫曼树来实现对应的操作,哈夫曼树是为每个结点增加一个权值,权值大的结点离根要尽可能的近,我们就可以将所有的字符视作只有一个根结点的树,将结点权值小的两个子树进行合成组成一颗新树,两个子树的权值之和作为新树的权值,这一颗新树与剩余的所有树组成一个新的集合,然后从中选取两个树进行上述过程,如此重复下去,直到剩下一棵树,这棵树就是哈夫曼树。图示如下:
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

如此进行下去最后只剩下一棵树:
在这里插入图片描述

这就是哈夫曼树,所以只需要将字母出现的次数作为权值,按照上述规则我们就能够生成一颗哈夫曼树。代码如下:

#include<stdio.h>
#include<stdlib.h>
struct BinaryTreeNode{int weight;char val;struct BinaryTreeNode * left;struct BinaryTreeNode * right;
};
//对子树按照权值进行降序排列,这样只操作最后面的两棵树就行了
void sort(struct BinaryTreeNode ** p, int length){for(int i=0;i<length-1;i++){for(int j=0; j<length-1; j++){if(p[j]->weight<p[j+1]->weight){struct BinaryTreeNode * t = p[j];p[j] = p[j+1];p[j+1] = t;}}}
}
//创建哈夫曼树
struct BinaryTreeNode * InitHuffmanTree(struct BinaryTreeNode ** p, int length){struct BinaryTreeNode * root = (struct BinaryTreeNode *)malloc(sizeof(struct BinaryTreeNode));while(length!=2){sort(p, length);root->left = (struct BinaryTreeNode *)malloc(sizeof(struct BinaryTreeNode));*(root->left) = *p[length-2];root->right = (struct BinaryTreeNode *)malloc(sizeof(struct BinaryTreeNode));*(root->right) = *p[length-1];root->val = 0;root->weight = p[length-2]->weight+p[length-1]->weight;free(p[length-1]);free(p[length-2]);p[length-2] = root;root = (struct BinaryTreeNode *)malloc(sizeof(struct BinaryTreeNode));length -= 1;}root->left = p[length-2];root->right = p[length-1];root->weight = p[length-2]->weight+p[length-1]->weight;return root;
}
//前序遍历
void preOrderTraversal(struct BinaryTreeNode *root){if(root!=NULL){printf("%d ", root->weight);preOrderTraversal(root->left);preOrderTraversal(root->right);	}
}
//中序遍历
void inOrderTraversal(struct BinaryTreeNode *root){if(root!=NULL){inOrderTraversal(root->left);printf("%d ", root->weight);inOrderTraversal(root->right);	}
}
int main(){int n;char code[4][20];printf("请问你有多少个字符需要进行编码:");scanf("%d", &n);struct BinaryTreeNode ** p = (struct BinaryTreeNode **)malloc(sizeof(int)*n);printf("请按顺序输入字符与其出现的次数。\n");for(int i=0; i<n; i++){p[i] = (struct BinaryTreeNode *)malloc(sizeof(struct BinaryTreeNode));p[i]->left = NULL;p[i]->right = NULL;printf("请输入字符:");getchar();scanf("%c", &p[i]->val);getchar();printf("请输入字符出现的次数:");scanf("%d", &p[i]->weight);}printf("请确认你刚才输入的信息:\n");for(int i=0; i<n; i++){printf("字符%c,出现%d次\n", p[i]->val, p[i]->weight);}struct BinaryTreeNode * root = InitHuffmanTree(p, n);printf("此哈夫曼树的权值前序序列为:");preOrderTraversal(root);printf("\n此哈夫曼树的中序序列为:");inOrderTraversal(root);return 0;
}

在这里插入图片描述

根据权值的前序序列与中序序列可以建立如下二叉树:
在这里插入图片描述

因为出现在叶子结点的才是字符,所以我们可以直到权值为7的结点时’a’,权值为4的结点是’d’,权值为2的结点是’c’,权值为5的结点时’b’,即如下图所示:
在这里插入图片描述

按照哈夫曼树的建立规则进行手动建树,可以建出以下这个树:
在这里插入图片描述

可以看出这两棵树是等价的,只不过是左右孩子交换了下顺序,也就是说明了程序是正确的。接下来就是进行哈夫曼编码了。
向左为0,向右为1进行编码,进行二进制编码,可以写出下面的代码:

void HuffmanCode(struct BinaryTreeNode *root, char n[20], char p[][20], int length){//p用来存储编好的编码if(root!=NULL){switch(root->val){case 'a':	case 'b':case 'c':case 'd':int i;for(i=0;i<length;i++){p[root->val-'a'][i]=n[i];}p[root->val-'a'][i]='\0';}n[length++] = '0';n[length] = 0;HuffmanCode(root->left, n, p, length);length--;n[length++] = '1';n[length] = 0;HuffmanCode(root->right, n, p,length);}
}

对上面的树进行编码
在这里插入图片描述

运行结果:
在这里插入图片描述

可以看到确实生成了哈夫曼编码。

如果有什么地方讲的不好或者讲错的地方欢迎大家指出来,如果我所讲的对你们有帮助不要忘了点赞、收藏、关注哦!


我是你们的好伙伴apprentice_eye


一个致力于让知识变的易懂的博主。

相关文章:

数据结构:树详解

创建二叉树 给出了完整的先序遍历序列&#xff0c;子树为空用’#’表示&#xff0c;所以这样我们在通过先序遍历序列创建二叉树时我们直到先序遍历序列是先进行根结点&#xff0c;然后左子树最后右子树的顺序进行遍历的&#xff0c;所以对于完整的先序遍历序列我们可以直到先序…...

list1.Sort((m, n) => m.Id - n.Id); id是double类型的为什么回报错

问题产生的地方 原因 对于 double 类型的属性&#xff0c;不能直接使用减法运算符进行比较。减法运算符只能用于数值类型&#xff0c;而 double 是浮点数类型。 要在 double 属性上进行排序&#xff0c;可以使用 CompareTo 方法或者使用自定义的比较器。 更改 要在 double 属性…...

GoLang vs Python

Python和Go是两种非常不同的编程语言&#xff0c;它们在设计哲学、用途和特性方面有各自的优势和局限性。以下是它们的一些主要区别&#xff1a; 设计哲学: Python: 设计简洁明了&#xff0c;强调代码的可读性和简洁性。Python遵循"只有一种方式来做一件事"的原则。…...

Hello 2024(A~D,F1)

新年坐大牢 A - Wallet Exchange 题意&#xff1a;共有俩钱包&#xff0c;每回合从其中一个钱包中拿走一块钱&#xff0c;谁拿走最后一块钱谁赢。 思路&#xff1a;奇偶讨论即可。 // Problem: A. Wallet Exchange // Contest: Codeforces - Hello 2024 // URL: https://cod…...

Python+Torch+FasterCNN网络目标检测识别

程序示例精选 PythonTorchFasterCNN网络目标检测识别 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对《PythonTorchFasterCNN网络目标检测识别》编写代码&#xff0c;代码整洁&#xff0c;规…...

v8 pwn利用合集

文章目录 前置知识JS Object 相关Ignition 相关JIT - turboFan 相关starCTF2019 OOB【越界读写map字段】googleCTF2018 jit【浮点数精度丢失导致越界读写】数字经济线下 Browser【Object::toNumber中callback导致的越界写】前置知识 JS Object 相关 V8 中的对象表示 ==> 基…...

JVM:字节码

JVM&#xff1a;字节码 前言1. JVM概述1.1 JVM vs JDK vs JRE1.1.1 JVM1.1.2 JDK1.1.2.1 常用的JDK8是Oracle JDK 还是 OpenJDK 1.1.3 JRE1.1.4 三者之间的关系与区别 1.2 什么是字节码?采用字节码的好处是什么?1.3 Java 程序从源代码到运行的过程1.4 JVM的生命周期1.5 JVM架…...

常见网络设备及功能详解

网络设备 - 交换机 交换机&#xff1a;距离终端用户最近的设备&#xff0c;用于终端用户接入网络、对数据帧进行交换等。 交换机的功能&#xff1a; 终端设备&#xff08;PC、服务器等&#xff09;的网络接入二层交换&#xff08;Layer 2 Switching&#xff09; 网络设备 - …...

Python教程(20)——python面向对象编程基本概念

面向对象 类和对象初始化方法属性和方法self关键字继承多态 面向对象&#xff08;Object-oriented&#xff09;是一种常用的程序设计思想&#xff0c;它以对象作为程序的基本单元&#xff0c;将数据和操作封装在一起&#xff0c;通过对象之间的交互来实现程序的功能。 在面向对…...

C# Winform教程(一):MD5加密

1、介绍 在C#中&#xff0c;MD5&#xff08;Message Digest Algorithm 5&#xff09;是一种常用的哈希函数&#xff0c;用于将任意长度的数据转换为固定长度的哈希值&#xff08;通常是128位&#xff09;。MD5广泛用于校验数据完整性、密码存储等领域。 2、示例 创建MD5加密…...

Mongodb使用指定索引删除数据

回顾Mongodb删除语法 db.collection.deleteMany(<filter>,{writeConcern: <document>,collation: <document>,hint: <document|string>} ) 删除语法中&#xff0c;除了指定过滤器外&#xff0c;还可以指定写入策略&#xff0c;字符序和使用的索引。 …...

虾皮怎么选品:虾皮(Shopee)跨境电商业务成功的关键步骤

在虾皮&#xff08;Shopee&#xff09;平台上进行跨境电商业务&#xff0c;选品是至关重要的一环。有效的选品策略可以帮助卖家更好地了解市场需求&#xff0c;提高销售业绩和客户满意度。以下是一些成功的选品策略&#xff0c;可以帮助卖家在虾皮平台上取得更好的业务成绩。 先…...

QML —— 使用Qt虚拟键盘示例(附完整源码)

示例效果 使用"虚拟键盘"注意 &#xff08;例子的Qt版本:5.12.4&#xff09; 注意一&#xff1a;      /* 必须在main.cpp开始处加入如下代码&#xff0c;否则无法使用"虚拟键盘" */      qputenv(“QT_IM_MODULE”,QByteArray(“qtvirtualkeybo…...

Nacos 持久化及集群的搭建【微服务】

文章目录 一、统一配置管理二、微服务配置拉取三、配置热更新四、多环境共享配置五、Nacos 集群搭建1. 集群结构2. 初始化数据库3. 搭建集群 六、Nginx 反向代理七、启动项目测试 一、统一配置管理 案例练习的时候我们只有两个微服务&#xff0c;管理起来非常简单&#xff0c;但…...

win10下vscode+cmake编译C代码操作详解

0 工具准备 1.Visual Studio Code 1.85.1 2.cmake 3.24.01 前言 当我们只有一个.c文件时直接使用vscodeCode Runner插件即可完成编译&#xff0c;如果我们的工程很复杂包含多个.c文件时建议使用cmake来生成对应的make&#xff0c;指导编译器完成编译&#xff0c;否则会提示各…...

网络安全红队常用的攻击方法及路径

一、信息收集 收集的内容包括目标系统的组织架构、IT资产、敏感信息泄露、供应商信息等各个方面&#xff0c;通过对收集的信息进行梳理&#xff0c;定位到安全薄弱点&#xff0c;从而实施下一步的攻击行为。 域名收集 1.备案查询 天眼查爱企查官方ICP备案查询 通过以上三个…...

【基于openGauss2.1.0企业版安装X-Tuner参数调优工具】

【基于openGauss2.1.0企业版安装X-Tuner参数调优工具】 一、前提条件二、安装X-Tuner 2.1.0: 一、前提条件 已安装了openGauss2.1.0企业版 二、安装X-Tuner 2.1.0: 以root用户登录到服务器 安装以下依赖&#xff1a; yum -y groupinstall "Development tools" yum…...

SpringBoot+Vue轻松实现考试管理系统

简介 本系统基于 Spring Boot 搭建的方便易用、高颜值的教学管理平台&#xff0c;提供多租户、权限管理、考试、练习、在线学习等功能。主要功能为在线考试、练习、刷题&#xff0c;在线学习。课程内容支持图文、视频&#xff0c;考试类型支持考试、练习、问卷。 源码下载 网…...

详解Keras:keras.preprocessing.image

keras.preprocessing.image Keras 库中的一个模块&#xff0c;用于处理和增强图像数据&#xff0c;它提供了一些实用的函数&#xff0c;如图像的加载、预处理、增强等。 常用函数 1、load_img 用于加载图像文件&#xff0c;并返回一个 NumPy 数组表示该图像 示例 from ker…...

来瞅瞅Java 11都有啥新特性

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff01;今天小黑要和咱们聊聊Java 11&#xff0c;这个在Java发展史上占有一席之地的版本。说起Java&#xff0c;咱们都知道&#xff0c;它是一门历史悠久又持续发展的编程语言。Java不仅因其“一次编写&#xff0c;到处…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

OkHttp 中实现断点续传 demo

在 OkHttp 中实现断点续传主要通过以下步骤完成&#xff0c;核心是利用 HTTP 协议的 Range 请求头指定下载范围&#xff1a; 实现原理 Range 请求头&#xff1a;向服务器请求文件的特定字节范围&#xff08;如 Range: bytes1024-&#xff09; 本地文件记录&#xff1a;保存已…...

python执行测试用例,allure报乱码且未成功生成报告

allure执行测试用例时显示乱码&#xff1a;‘allure’ &#xfffd;&#xfffd;&#xfffd;&#xfffd;&#xfffd;ڲ&#xfffd;&#xfffd;&#xfffd;&#xfffd;ⲿ&#xfffd;&#xfffd;&#xfffd;Ҳ&#xfffd;&#xfffd;&#xfffd;ǿ&#xfffd;&am…...

中医有效性探讨

文章目录 西医是如何发展到以生物化学为药理基础的现代医学&#xff1f;传统医学奠基期&#xff08;远古 - 17 世纪&#xff09;近代医学转型期&#xff08;17 世纪 - 19 世纪末&#xff09;​现代医学成熟期&#xff08;20世纪至今&#xff09; 中医的源远流长和一脉相承远古至…...

网站指纹识别

网站指纹识别 网站的最基本组成&#xff1a;服务器&#xff08;操作系统&#xff09;、中间件&#xff08;web容器&#xff09;、脚本语言、数据厍 为什么要了解这些&#xff1f;举个例子&#xff1a;发现了一个文件读取漏洞&#xff0c;我们需要读/etc/passwd&#xff0c;如…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...