【数据结构】------C语言实现二叉树

                                                          作者主页:作者主页

                                                          数据结构专栏:数据结构

                                                         创作时间 :2024年5月20日

一、二叉树的定义

二叉树(Binary Tree) 是由n个结点构成的有限集(n≥0),n=0时为空树,n>0时为非空树。

对于非空树:

  • 有且仅有一个根节点
  • 除根结点外其他可分为两个不相交的子集Tl和Tr,分别称为T TT的左子树和右子树,从定义也可以看出二叉树与一般树的区别主要是两点,一是每个结点的度最多为2;二是结点的子树有左右之分,不能随意调换,调换后又是一棵新的二叉树。

二、二叉树的形态

五种基本形态:

三种特殊形态:

三、二叉树的性质

  1. 任意二叉树第 i ii 层最大结点数为2^(i-1)。(i>=1)
  2. 深度为 k  的二叉树最大结点总数为2^k-1个(满二叉树)

  3. 对于任意二叉树:

 

四、二叉树的存储

存的目的是为了取,而取的关键在于如何通过父结点拿到它的左右子结点,不同存储方式围绕的核心也就是这。

顺序存储:

使用一组地址连续的存储单元存储,例如数组。为了在存储结构中能得到父子结点之间的映射关系,二叉树中的结点必须按层次遍历的顺序存放。具体是:

  • 对于完全二叉树,只需要自根结点起从上往下、从左往右依次存储。
  • 对于非完全二叉树,首先将它变换为完全二叉树,空缺位置用某个特殊字符代替(比如#),然后仍按完全二叉树的存储方式存储。

假设将一棵二叉树按此方式存储到数组后,左子结点下标=2倍的父结点下标+1,右子节点下标=2倍的父结点下标+2(这里父子结点间的关系是基于根结点从0开始计算的)。若数组某个位置处值为#,代表此处对应的结点为空。

可以看出顺序存储非常适合存储接近完全二叉树类型的二叉树,对于一般二叉树有很大的空间浪费,所以对于一般二叉树,一般用下面这种链式存储。

链式存储:

对每个结点,除数据域外再多增加左右两个指针域,分别指向该结点的左孩子和右孩子结点,再用一个头指针指向根结点。对应的存储结构:

二叉树代码的实现:

首先我们要得到相应的自定义函数,然后再去一一实现他们

typedef int BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;}BTNode;//创建一颗树
BTNode* creatBT();//创建一个新节点
BTNode* BuyNode(int x);//前序遍历
void PrevOrder(BTNode* root);//计算节点个数
int TreeSize(BTNode* root);

由于我们接下来的前序、中序、后序遍历都需要一个二叉树,所以我们这里要先创建一颗二叉树才可以。

创建一个简易二叉树:

//创建一个新节点
BTNode* BuyNode(int x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc failed");exit(0);}newnode->data = x;newnode->left = newnode->right =NULL;return newnode;
}BTNode* creatBT()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}

前序遍历:

//前序遍历
void PrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->data);//输出当前数值PrevOrder(root->left);//然后递归进行PrevOrder(root->right);
}

中序遍历:

//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->left);//先递归,等到最后一个之后再进行输出printf("%d ", root->data);InOrder(root->right);
}

后序遍历:

//后序遍历
void BackOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BackOrder(root->left);BackOrder(root->right);printf("%d ", root->data);
}

节点个数:

//节点个数
int treesize(BTNode* root)
{if (root == NULL)return 0;else return treesize(root->left) + treesize(root->right) + 1 ;
}

另一种方式:

int TreeSize(BTNode* root)
{static int size = 0;//用局部静态变量,只初始化一次。if (root == NULL){return 0;}else{++size;}TreeSize(root->left);TreeSize(root->right);return size;
}

求叶子节点个数:

//求叶子节点个数
int TreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}

树的高度:

int TreeHeigh(BTNode* root)
{if (root == NULL){return 0;}int leftheight = TreeHeigh(root->left);int rightheight = TreeHeigh(root->right);return leftheight > rightheight ?leftheight + 1 : rightheight + 1;
}

总代码:

Tree.h:

#pragma once
#include<iostream>
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int BTDataType;typedef struct BinaryTreeNode
{BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right;}BTNode;//创建一颗树
BTNode* creatBT();//创建一个新节点
BTNode* BuyNode(int x);//前序遍历
void PrevOrder(BTNode* root);//计算节点个数
int TreeSize(BTNode* root);

test.c:

#include"Tree.h"//创建一个新节点
BTNode* BuyNode(int x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc failed");exit(0);}newnode->data = x;newnode->left = newnode->right =NULL;return newnode;
}BTNode* creatBT()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;return node1;
}//前序遍历
void PrevOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}printf("%d ", root->data);//输出当前数值PrevOrder(root->left);//然后递归进行PrevOrder(root->right);
}//中序遍历
void InOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}InOrder(root->left);//先递归,等到最后一个之后再进行输出printf("%d ", root->data);InOrder(root->right);
}//后序遍历
void BackOrder(BTNode* root)
{if (root == NULL){printf("N ");return;}BackOrder(root->left);BackOrder(root->right);printf("%d ", root->data);
}//节点个数
int treesize(BTNode* root)
{if (root == NULL)return 0;else return treesize(root->left) + treesize(root->right) + 1 ;
}int TreeSize(BTNode* root)
{static int size = 0;//用局部静态变量,只初始化一次。if (root == NULL){return 0;}else{++size;}TreeSize(root->left);TreeSize(root->right);return size;
}//求叶子节点个数
int TreeLeafSize(BTNode* root)
{if (root == NULL){return 0;}if (root->left == NULL && root->right == NULL){return 1;}return TreeLeafSize(root->left) + TreeLeafSize(root->right);
}int TreeHeigh(BTNode* root)
{if (root == NULL){return 0;}int leftheight = TreeHeigh(root->left);int rightheight = TreeHeigh(root->right);return leftheight > rightheight ?leftheight + 1 : rightheight + 1;
}int main()
{BTNode* root = creatBT();InOrder(root);printf("\n");int ret = TreeSize(root);std::cout << "TreeSize:" << ret << std::endl;ret = treesize(root);std::cout << "TreeSize:" << ret << std::endl;ret = TreeLeafSize(root);std::cout << "TreeLeafSize:" << ret << std::endl;int heigh = TreeHeigh(root);std::cout << "TreeHeigh:" << heigh << std::endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/16173.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

接口自动化核心模块Requests详解(一)

一、Requests简介 Python的Requests库是一个功能强大且简洁的库&#xff0c;提供了简单易用的接口来处理HTTP请求。 二、Requests的使用步骤 2.1 安装Requests库 在终端命令行&#xff0c;使用pip命令进行安装&#xff0c; pip install requests 2.2 Requests库常用方法…

腾讯Java社招面试题真题,最新面试题

Java中synchronized和ReentrantLock有什么区别&#xff1f; 1、锁的实现方式不同&#xff1a; synchronized是JVM层面的锁&#xff0c;主要依赖于监视器对象&#xff08;monitor&#xff09;实现。ReentrantLock是JDK层面的锁&#xff0c;通过Java代码实现&#xff0c;提供了更…

语雀——云知识库/笔记

对于日常进行学习/创作或是记录学习、工作内容与心得的群体来说&#xff0c;能够及时同步的云笔记应用有着广泛的应用场景。近期&#xff0c;我也探索了许多款不同的软件应用&#xff0c;今天来分享一款很有特点的应用——语雀。 语雀&#xff0c;为每一个人提供优秀的文档和知…

1.6 什么是程序-编译与调试

目录 1 程序的作用 2 新建项目及编译运行 2.1 新建项目 2.2 HelloWorld 程序说明 2.3 printf 打印输出 2.4 注释 3 程序的编译过程及项目位置 4 断点及调试窗口设置 5 学习C语言后的境界 1 程序的作用 如下图所示&#xff0c;我们编写了一个可以做加法的程序&#xf…

vue3 vite项目配置了proxy代理情况下查看真实的接口调用地址

vite配置了proxy代理情况下如何查看真实的接口调用地址? 使用vite进行代理 在vite.config.ts配置了代理 在浏览器查看请求头和响应头发现只有代理前的url&#xff0c;没有显示代理后的路径 然后发现一个bypass函数&#xff0c;但是此函数只能修改res响应头的数据&#xff0…

C语言基础-链表和数组的区别

在C语言中&#xff0c;链表&#xff08;Linked List&#xff09;和数组&#xff08;Array&#xff09;是两种常用的数据结构&#xff0c;它们在数据存储和访问上各有其独特的作用和优势。以下是对这两种数据结构的作用以及它们之间的不同点的详细说明&#xff1a; 数组&#x…

Dockerfile文件详细介绍

前言 Dockerfile是一个文本文件&#xff0c;包含了用于构建Docker镜像的所有命令和说明。它定义了容器的运行环境、依赖以及启动方式&#xff0c;是创建Docker镜像的核心部分。 由于制作镜像的过程中&#xff0c;需要逐层处理和打包&#xff0c;比较复杂&#xff0c;所以Docke…

实战复盘:内网环境渗透ms-SQL数据库

渗透环境&#xff1a;如下图所示&#xff0c;web服务器、ms-SQL服务器、PC客户端在同一个网络中&#xff0c;彼此之间&#xff0c;没有路由器或防火墙的隔离&#xff0c;这是一种危险的网络结构&#xff0c;入侵ms-SQL服务器&#xff0c;非常容易。&#xff08;实战中&#xff…

整理了10个靠谱且热门的赚钱软件,适合普通人长期做的赚钱副业

作为一名普通的上班族&#xff0c;我们每天都在辛勤工作&#xff0c;但工资的增长速度却如同蜗牛般缓慢。不过&#xff0c;别担心&#xff0c;信息时代总是带给我们无尽的惊喜&#xff01;今天&#xff0c;我将为大家推荐一些赚钱的宝藏软件&#xff0c;让你在闲暇之余轻松实现…

Java-Zookeeper

zookeeper是什么 一个分布式、开源的分布式应用程序协调服务&#xff0c;具有配置维护、域名服务、分布式同步、组服务等 zookeeper有哪些功能 功能简介集群管理监控节点状态、运行请求等主节点选举主节点挂掉之后会执行新主选举分布式锁zookeeper提供两种锁&#xff1a;独占…

IEDA常用快捷键(后续更新ing)

1. 快速生成语句 1.快速生成main()方法 psvm或者main回车 2.快速生成输出语句 sout,回车 3.快速生成for循环 fori或者itar,回车 2.快捷键 含义操作查找文本CtrlF替换文本CtrlR单行注释Ctrl/多行注释CtrlShift/格式化CtrlAltL复制当前内容至下一行CtrlD补全代码Alt/快速生成…

RAGs:自动化评估 RAG 示例代码

文章目录 原理忠实度&#xff08;Faithfulness&#xff09;答案相关性&#xff08;Answer Relevance&#xff09;上下文相关性&#xff08;Context Relevance&#xff09;上下文召回率&#xff08;Context Recall&#xff09;答案正确性&#xff08;Answer Correctness&#xf…

C# 机构仿真实例

1、实现连杆带动滑块运动 一个连杆旋转带动另一个连杆&#xff0c;另一个连杆拖动滑块&#xff0c;点击“开始”按钮开始运动&#xff0c;再点击按钮&#xff0c;则停止运动。 2、实现程序 #region 机构仿真Image image null;Timer timer new Timer();int width 0;int heig…

一千题,No.0027(Phone Desktop)

描述 Little Rosie has a phone with a desktop (or launcher, as it is also called). The desktop can consist of several screens. Each screen is represented as a grid of size 53, i.e., five rows and three columns. There are x applications with an icon size o…

【网络安全】社会工程学攻击与防范

一、社会工程学概述 1、社会工程学的定义 通过利用人们的心理弱点、本能反应、好奇心、信任、贪婪等一些心理陷阱进行的诸如欺骗、伤害、信息盗取、利益谋取等对社会及人类带来危害的行为或方法。 当网络恶意攻击者无法通过纯粹的计算机技术达到目的时&#xff0c;高超的情商…

9.Redis之list类型

list相当于链表、数据表 1.list类型基本介绍 列表中的元素是有序的"有序"的含义,要根据上下文区分~~有的时候,谈到有序,指的是"升序","降序”有的时候,谈到的有序,指的是, 顺序很关键~~如果把元素位置颠倒,顺序调换.此时得到的新的 List 和之前的 Li…

js简单综合案例之简易ATM取款机、渲染表格案例、封装时间函数

这里写目录标题 简易ATM取款机要求代码实现 渲染表格案例要求代码实现 封装时间函数要求代码实现 简易ATM取款机 要求 1.弹出弹窗&#xff0c;让用户输入数字选择操作 2.初始值金额为100&#xff0c;计算每次操作后的剩余金额变化 3.一直弹出弹窗直到用户输入4&#xff0c;跳…

OpenCV SIFT特征描述子(GPU版本)

文章目录 一、简介二、测试过程三、实现效果参考资料一、简介 这里主要测试一下SIFT图像描述子的GPU版本。SIFT图像描述子,全称Scale-Invariant Feature Transform(尺度不变特征变换),是计算机视觉和图像处理领域中一种非常重要的局部特征描述子。它主要用于图像的特征点检…

新闻稿海外媒体投稿,除了美联社发稿(AP)和彭博社宣发(Bloomberg),还有哪些优质的国外媒体平台可以选择

发布高质量的新闻稿到海外媒体&#xff0c;除了美联社发稿&#xff08;AP&#xff09;和彭博社发稿&#xff08;Bloomberg&#xff09;&#xff0c;还有许多其他优质的媒体平台可以选择。以下是一些受欢迎和高效的海外媒体发布平台&#xff1a; 路透社 (Reuters) 路透社是全球最…

Webpack Bundle Analyzer:深入分析与优化你的包

Webpack Bundle Analyzer是一个用于可视化的工具&#xff0c;它可以帮助你分析Webpack打包后的输出文件&#xff0c;查看哪些模块占用了最多的空间&#xff0c;从而进行优化。 2500G计算机入门到高级架构师开发资料超级大礼包免费送&#xff01; 首先&#xff0c;你需要安装W…