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

数据结构:树

 树:

    只有一个前驱,但是可以有多个后继
    根节点:最顶层节点(没有前驱)
    分支节点:有前驱也有后继
    叶子节点:没有后继的节点
    层:根节点所在为第一层,每过一个分支节点,层数+1 
    深度: 从根节点出发到达节点的分支节点个数称为该节点的深度
    高度:从叶子节点出发到该节点最大的节点个数称为该节点的高度

    树的高度:整个树形结构中高度最高的节点的高度称为树的高度
    树的深度:整个树形结构中深度最深的节点的深度称为树的深度
    树的层数 == 树的高度 == 树的深度

    节点的度: 叶子节点度数为0 
              节点的后继的个数

二叉树:

  所有节点中最大度数为2的树形结构

    满二叉树:满二叉树是一种特殊的二叉树,其中每个层级的节点数都是最大值,即每个层级都是完全填充的
    完全二叉树:所有节点展开后,节点编号排列连续

    二叉树特点:叶子节点、只有左孩子、只有右孩子、左右孩子都有
    满二叉树:二叉树第k层最多有2^(k-1)个节点 
             满二叉树有k层,则所有节点数为 2^k -1

    二叉树的三种遍历方法:


    1.前序遍历:根左右

A  B  D  E  H  C  F  I  G
    2.中序遍历:左根右

D  B  E  H  A  F  I  C  G
    3.后续遍历:左右根

D  H  E  B  I  F  G  C  A

二叉树结构体

typedef struct node
{int No; //节点序号char data;//也可以是char类型的struct node *pLeftChild;//左孩子struct node *pRightChild;//右孩子}BinTree;

创建完全二叉树

BinTree *CreateBinTree(int Start,int End)
{BinTree *pRoot=NULL;pRoot=malloc(sizeof(BinTree));if(pRoot==NULL){return NULL;}pRoot->No=Start;pRoot->pLeftChild=NULL;pRoot->pRightChild=NULL;if(2*Start<=End){pRoot->pLeftChild = CreateBinTree(2*Start,End);}if(2*Start+1<=End){pRoot->pRightChild = CreateBinTree(2*Start+1,End);}return pRoot;
}

前序遍历(递归)

int PreOrderBinTree(BinTree *pRoot)
{//printf("%d ",pRoot->No);printf("%c ",pRoot->data);if(pRoot->pLeftChild!=NULL){PreOrderBinTree(pRoot->pLeftChild);}if(pRoot->pRightChild!=NULL){PreOrderBinTree(pRoot->pRightChild);}return 0;
}

中序遍历(递归)

int InOrderBinTree(BinTree *pRoot)
{if(pRoot->pLeftChild!=NULL){InOrderBinTree(pRoot->pLeftChild);}//printf("%d ",pRoot->No);printf("%c ",pRoot->data);if(pRoot->pRightChild!=NULL){InOrderBinTree(pRoot->pRightChild);}return 0;
}

后序遍历(递归)

int PostOrderBinTree(BinTree *pRoot)
{if(pRoot->pLeftChild!=NULL){PostOrderBinTree(pRoot->pLeftChild);}if(pRoot->pRightChild!=NULL){PostOrderBinTree(pRoot->pRightChild);}//printf("%d ",pRoot->No);printf("%c ",pRoot->data);return 0;
} 

销毁二叉树(后序遍历思想)

int DestroyBinTree(BinTree **pRoot)
{if((*pRoot)->pLeftChild!=NULL){DestroyBinTree(&(*pRoot)->pLeftChild);}if((*pRoot)->pRightChild!=NULL){DestroyBinTree(&(*pRoot)->pRightChild);}free((*pRoot));*pRoot=NULL;return 0;
}

创建不完全二叉树

//输入#代表此节点不存在
//节点存在则再次递归调用本函数,创建其左右子树

BinTree *CreateUncompleteTree(void)
{BinTree *pRoot=NULL;char Tmpdata=0;scanf(" %c",&Tmpdata);if(Tmpdata=='#'){return NULL;}else{pRoot=malloc(sizeof(BinTree));if(pRoot==NULL){return NULL;}pRoot->data=Tmpdata;pRoot->pLeftChild=CreateUncompleteTree();pRoot->pRightChild=CreateUncompleteTree();}return pRoot;
}

获得树的高度

//每个节点的高度等于 左子树或右子树中较高的子树高度 +1

int GetBinTreeHeight(BinTree *pRoot)
{int LeftHeight=0;int RightHeight=0;if(pRoot==NULL){return 0;}LeftHeight = GetBinTreeHeight(pRoot->pLeftChild);RightHeight=GetBinTreeHeight(pRoot->pRightChild);return (LeftHeight>RightHeight?LeftHeight:RightHeight)+1;
}

定义链表结构体(使用内核链表)

typedef struct Data
{struct list_head node;BinTree *pData;
}Data_t;

 层次遍历

使用队列实现层次遍历

算法思想:

  • 初始化:创建一个队列,并将根节点加入队列中。
  • 循环处理:当队列不为空时,进行循环。
    • 队列中第一个节点出队。
    • 访问该节点(进行你需要的操作,如打印节点的值)。
    • 如果该节点有左子节点,则将左子节点加入队列。
    • 如果该节点有右子节点,则将右子节点加入队列。
  • 结束:当队列为空时,表示所有节点都已经遍历完,算法结束。
int LayerOrderBinTree(BinTree *pRoot)
{struct list_head head;Data_t *pTmpNode=NULL;Data_t *pFreeNode=NULL;if(pRoot==NULL){return -1;}//创建链式队列INIT_LIST_HEAD(&head);//为根节点申请一块链式节点的空间pTmpNode=malloc(sizeof(Data_t));if(pTmpNode==NULL){return -1;}//链式节点的pData挂载根节点pTmpNode->pData=pRoot;//根节点入队list_add_tail(&pTmpNode->node,&head);while(!list_empty(&head)){//找到队头(要出栈的节点)pFreeNode=list_entry(head.next,Data_t,node);//打印队头printf(" %c",pFreeNode->pData->data);//判断要出栈的节点是否有左孩子,左孩子存在则入队if(pFreeNode->pData->pLeftChild!=NULL){pTmpNode=malloc(sizeof(Data_t));if(pTmpNode==NULL){return -1;}pTmpNode->pData=pFreeNode->pData->pLeftChild;list_add_tail(&pTmpNode->node,&head);}//判断要出栈的节点是否有右孩子,右孩子存在则入队if(pFreeNode->pData->pRightChild!=NULL){pTmpNode=malloc(sizeof(Data_t));if(pTmpNode==NULL){return -1;}pTmpNode->pData=pFreeNode->pData->pRightChild;list_add_tail(&pTmpNode->node,&head);}//队头出栈list_del(&pFreeNode->node);//释放为此节点申请的空间free(pFreeNode);}return 0;
}

前序遍历(非递归)

算法思想

  1. 初始化:创建一个空栈用于存储节点,同时设定一个指针(或称为当前访问节点)指向根节点。

  2. 访问当前节点:当栈不为空或当前节点不为空时,进行循环。

    • 如果当前节点不为空,则首先访问(处理)当前节点(例如,打印其值),然后将当前节点推入栈中,并转向其左子节点(即,将当前节点设为左子节点)。
    • 如果当前节点为空,则从栈中弹出一个节点作为新的当前节点,并转向其右子节点(即,将当前节点设为右子节点)。
  3. 结束条件:当栈为空且当前节点也为空时,表示所有节点都已遍历完毕,算法结束。

int PreOrderBinTreeByStack(BinTree *pRoot)
{struct list_head stackhead;Data_t *pTmpNode=NULL;Data_t *pFreeNode=NULL;BinTree *pTreeNode=NULL;if(pRoot==NULL){return -1;}//初始化链式栈INIT_LIST_HEAD(&stackhead);pTreeNode=pRoot;while(1){//每个左孩子节点入栈while(NULL!=pTreeNode){pTmpNode=malloc(sizeof(Data_t));if(pTmpNode==NULL){return -1;}pTmpNode->pData=pTreeNode;//入栈前打印此节点printf(" %c",pTreeNode->data);list_add(&pTmpNode->node,&stackhead);pTreeNode=pTreeNode->pLeftChild;}if(list_empty(&stackhead)){break;}//此时的栈顶节点出栈pFreeNode=list_entry(stackhead.next,Data_t,node);list_del(&pFreeNode->node);//将此节点的右子树的所有左孩子循环入栈pTreeNode=pFreeNode->pData->pRightChild;free(pFreeNode);}return 0;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • selenium使用指南
  • 在centos系统中kill掉指定进程
  • Vue3 ref 和 reactive 的区别
  • Linux操作文件和文件夹的常用基础命令
  • RTC相关
  • vmware解决虚拟机空间占用不断增大问题
  • Eclipse 自定义字体大小
  • Android 模拟器的简单操作
  • 【算法】演员~评论家方法
  • 集成电路学习:什么是DAC数模转换器
  • 巧用 HTML 列表:<ul>、<ol>、<dl>的实用指南
  • 使用Python写贪吃蛇游戏
  • 计算机网络概述(分组延时、丢失和吞吐量)
  • python-矩阵交换行
  • 基于detectron2框架的深度学习模型载入自定义数据集
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • express + mock 让前后台并行开发
  • Python爬虫--- 1.3 BS4库的解析器
  • SegmentFault 技术周刊 Vol.27 - Git 学习宝典:程序员走江湖必备
  • vue和cordova项目整合打包,并实现vue调用android的相机的demo
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 订阅Forge Viewer所有的事件
  • 构造函数(constructor)与原型链(prototype)关系
  • 看域名解析域名安全对SEO的影响
  • 学习Vue.js的五个小例子
  • python最赚钱的4个方向,你最心动的是哪个?
  • 关于Android全面屏虚拟导航栏的适配总结
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • # 职场生活之道:善于团结
  • #include到底该写在哪
  • #在线报价接单​再坚持一下 明天是真的周六.出现货 实单来谈
  • (1)bark-ml
  • (1)svelte 教程:hello world
  • (35)远程识别(又称无人机识别)(二)
  • (C语言)球球大作战
  • (python)数据结构---字典
  • (ZT)出版业改革:该死的死,该生的生
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (算法)大数的进制转换
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • .NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划
  • .net core使用ef 6
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • .Net 高效开发之不可错过的实用工具
  • .net 逐行读取大文本文件_如何使用 Java 灵活读取 Excel 内容 ?
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .net和jar包windows服务部署
  • .NET面试题(二)
  • @property @synthesize @dynamic 及相关属性作用探究
  • [ 常用工具篇 ] POC-bomber 漏洞检测工具安装及使用详解
  • [20150629]简单的加密连接.txt