数据结构-二叉树和堆的实现
二叉树
- 树的概念和结构
- 概念
- 结构
- 树的其他概念名词
- 树的孩子兄弟表示法
- 树的实际应用
- 二叉树的概念和结构
- 概念
- 特殊的二叉树
- 二叉树的性质
- 二叉树的存储结构
- 二叉树的顺序结构-堆
- 堆的实现
- 堆的向下调整算法
- 堆的创建
- 堆的销毁
- 堆得插入
- 堆的删除
- 堆顶的数据
- 堆数据的个数
- 判断堆是否为空
- 堆排序
- 二叉树的链式结构
- 二叉树的实现会在下一章详细写出来
树的概念和结构
概念
树是一种非线性的数据结构,它是由n(n>=0)个有限节点组成一个具有层次关系的集合。
把它叫做树是因为它看起来像一颗倒挂的树,也就是说根是朝上的,叶子朝下。
1.树有一个特殊节点,称为根节点,根节点没有前驱节点。
2.除了根节点外,其余节点被分成M(M>0)个互不相交的集合T1、T2、.....等,其中每个集合又是一棵结构与树类似的子树。
每颗子树的根节点有且只有一个前驱,可以有0个或多个后继。
树是递归定义的。
结构
注意:1.子树能不能相交的2.除了根节点外,每个节点有且只有一个父节点3.一颗N个节点的树有N-1条边
树的其他概念名词
节点的度:一个节点含有子树的个数称为节点的度;上树A的度为2
叶节点或终端节点:度为0的节点称为叶节点;如上图的D、E、F
非终端节点或分支节点:度不为0的节点;如上图的B、C
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;如上图的A是B的父节点
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;如上图B是A的子节点
兄弟节点:具有相同父节点的节点互称为兄弟节点;如上图B、C是兄弟节点
树的度:一棵树中,最大节点的度称为树的度;如上图树的度为2
节点的层次:从根开始定义,根为第一层,根的子节点为第二层,以此类推
树的高度或深度:树中节点的最大层次
堂兄弟节点:双亲在同一层次的节点互为堂兄弟;如上图E、F
节点的祖先:从根到该节点所经历分支上的所有节点;如上图A是所有节点的祖先
子孙:以某节点为根的子树中任一节点都称为该节点的子孙;如上图所有节点都是A的子孙
森林:由m(m>0)颗互不相交的树的集合称为森林;
树的孩子兄弟表示法
typedef int DataType;
typedef struct Node
{struct Node* firstChild1; //第一个孩子节点struct Node* pNextBrother; //孩子的兄弟节点DataType data;
}Node;
树的实际应用
计算机中的文件系统都是用的树型结构,Windows、Linux等
二叉树的概念和结构
概念
一颗二叉树是节点的一个有限集合,该集合或者为空,或者是由一个根节点加上两颗分别称为左子树和右子树的二叉树组成。
特点:1.每个节点最多有两棵子树,即二叉树不存在度大于2的节点。2.二叉树的子树有左右之分,其子树的次序不能颠倒。上面的树就是二叉树,二叉树也可以是但分支的,比如下图中都是二叉树
特殊的二叉树
1.满二叉树:一个二叉树,如果每一层的节点都达到最大值,则这个二叉树就是满二叉树。
如果一个满二叉树层数为k,且节点总数为(2^k)-1个,那么它就是满二叉树
2.完全二叉树:完全二叉树是由满二叉树引出来的,对于深度为k,节点为n的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中编号从1至n的节点一一对应时称之为完全二叉树。
满二叉树是一种特殊的完全二叉树。
二叉树的性质
1.若规定根节点的层数为1,则一颗非空二叉树的第i层最多有2^(i-1)个节点
2.若规定根节点的层数为1,则深度为h的二叉树的最大节点数是2^h-1个
3.对任何一颗二叉树,如果度为0的叶子节点个数为n0,度为2的分支节点为n2,则有n0=n2+1。(没有孩子的节点比有两个孩子的节点个数多一)
4.若规定根节点的层数为1,具有n个节点的满二叉树的深度,h=log2(n+1)(以2为底,n+1为对数),深度为h,节点n=2^h-1
5.对于具有n个节点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的节点:
若i>0,双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
若2i+1<n,左孩子序号:2i+1,否则无左孩子
若2i+2<n,右孩子序号:2i+2,否则无右孩子
二叉树的存储结构
一种是顺序结构,一种是链式结构
现实中顺序结构一般是用来实现堆的(完全二叉树)链式结构有:二叉链表和三叉链表,本文先学二叉链表typedef int BTDataType;
struct BinaryTreeNode
{struct BinaryTreeNode* pLeft; //左孩子struct BinaryTreeNode* pRight; //右孩子BTDataType data; //数据
};
二叉树的顺序结构-堆
普通的二叉树是不适合用数组存储的,因为可能会造成大量的空间浪费。
而完全二叉树更适合使用顺序结构存储。
堆:如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储
在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为
小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆
大堆:树中所有得父亲节点都大于等于孩子
小堆:树中所有得父亲节点都小于等于孩子
堆的实现
堆的向下调整算法
前提:二叉树的左右子树必须都是小堆或者大堆。
Swap(int* a,int* b)
{int tmp = *a;*a = *b;*b = tmp;
}AdjustDown(int* a, int parent, int size)
{int child = 2*parent + 1;while(child<size){if(child + 1 < size && a[child] > a[child+1]) //选出小的那个{child++;}if(a[parent] > a[child]){Swap(&a[parent],&a[child]);parent = child;child = 2*parent + 1;}else{break;}}
}int main()
{int a[] = { 27,15,19,18,28,34,65,49,25,37 };int k = sizeof(a) / sizeof(a[0]);AdjustDown(a, 0, k);for (int i = 0; i < k; i++){printf("%d ", a[i]);}printf("\n");return 0;
}
堆的创建
建堆就是把二叉树分成多个小二叉树,然后分别用向下调整算法把二叉树调成大堆
从右下角的二叉树开始
typedef int HPDataType;
typedef struct Heap
{HPDataType* a;int size;int capacity;
}Heap;void HeapCreate(Heap* hp, HPDataType* a, int n)
{assert(hp);hp->a = (HPDataType*)malloc(sizeof(HPDataType) * n);if (hp->a == NULL){perror("HeapCreate malloc fail");exit(-1);}hp->size = hp->capacity = n;memcpy(hp->a, a, sizeof(HPDataType)*n);for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(hp->a, i, n);}
}
堆的销毁
void HeapDestroy(Heap* hp)
{assert(hp);free(hp->a);hp->a = NULL;hp->size = hp->capacity = 0;
}
堆得插入
//在堆的最后面插入数据,然后在向上调整
void AdjustUp(int* a, int child)
{int parent = (child - 1) / 2;while (child > 0){if (a[parent] > a[child]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}void HeapPush(Heap* hp, HPDataType x)
{assert(hp);if (hp->capacity == hp->size){hp->capacity *= 2;HPDataType* tmp = (HPDataType*)realloc(hp->a, sizeof(HPDataType) * hp->capacity);if (tmp == NULL){perror("HeapPush realloc fail");exit(-1);}hp->a = tmp;}hp->a[hp->size] = x;hp->size++;AdjustUp(hp->a, hp->size - 1); //向上调整算法
}
堆的删除
//删除的是堆顶的数据
void HeapPop(Heap* hp)
{assert(hp);Swap(&hp->a[0], &hp->a[hp->size-1]);hp->size--;//AdjustDown(hp->a, 0,hp->size);HeapSoft(hp); //堆的排序,后面有
}
堆顶的数据
HPDataType HeapTop(Heap* hp)
{assert(hp);assert(hp->size > 0);return hp->a[0];
}
堆数据的个数
int HeapSize(Heap* hp)
{assert(hp);return hp->size;
}
判断堆是否为空
int HeapEmpty(Heap* hp)
{assert(hp);return hp->size;
}
堆排序
对堆进行排序,先建堆,然后把堆顶的数据和最后一位数据调换位置,在对剩下的数据重新建堆
排升序要建大堆,因为如果建小堆,第一次建堆选出最小的数和最后一位换,这时候找次小的,堆的结构被打乱,还要重新建堆,效率太差,建大堆就是把最大的放到最后一位,然后剩下的数进行向下调整
排降序建小堆
void HeapSoft(Heap* hp)
{assert(hp);for (int i = (hp->size - 1 - 1) / 2; i >= 0; i--){AdjustDown(hp->a, i, hp->size);}int end = hp->size - 1;while (end > 0){Swap(&hp->a[0], &hp->a[end]);AdjustDown(hp->a, 0, end);end--;}
}
二叉树的链式结构
typedef char BTDataType;
typedef struct BinaryTreeNode
{struct BinartTreeNode* leftChild; //左孩子struct BinartTreeNode* rightChild; //右孩子BTDataType data;
}BTNode;
二叉树的实现会在下一章详细写出来
数据结构-二叉树和堆的实现相关推荐
- DSt:数据结构的最强学习路线之数据结构知识讲解与刷题平台、刷题集合、问题为导向的十大类刷题算法(数组和字符串、栈和队列、二叉树、堆实现、图、哈希表、排序和搜索、动态规划/回溯法/递归/贪心/分治)总
DSt:数据结构的最强学习路线之数据结构知识讲解与刷题平台.刷题集合.问题为导向的十大类刷题算法(数组和字符串.栈和队列.二叉树.堆实现.图.哈希表.排序和搜索.动态规划/回溯法/递归/贪心/分治)总 ...
- 数据结构——二叉树总结
数据结构-二叉树总结 写在前面 二叉树遍历 递归实现先.中.后序遍历 非递归遍历 先序非递归 中序非递归 后序非递归 层次遍历 二叉树还原 先序中序建树 后序中序建树 层次中序建树 二叉树应用 二叉查 ...
- 3. 数据结构--二叉树 BST AVL树 Huffman
数据结构–二叉树 KEY:(不敢相信没有堆-) 二叉树的定义及其主要特征 ☑️ 二叉树的顺序存储结构和链式存储结构实现 二叉树的遍历及应用 二叉排序(查找.检索)树 (BST) 平衡的二叉检索树- A ...
- 顺序二叉树(堆)与链式二叉树的C语言实现
文章目录 树的概念及结构 树的概念 树的相关概念 树的表示 树在实际中的运用 二叉树的概念及结构 二叉树的概念 现实中的二叉树 特殊的二叉树 二叉树的性质 二叉树的存储结构 二叉树的顺序结构及实现 二 ...
- 数据结构 -- 二叉树
这篇文章介绍的是经典的数据结构--二叉树,在这篇文章里介绍了几乎二叉树的所有操作. 二叉树给我们最重要的印象莫过于递归,因为这棵树就是递归的,所以,我在解决各个问题时大部分都用 ...
- 数据结构 - 二叉树 - 面试中常见的二叉树算法题
数据结构 - 二叉树 - 面试中常见的二叉树算法题 数据结构是面试中必定考查的知识点,面试者需要掌握几种经典的数据结构:线性表(数组.链表).栈与队列.树(二叉树.二叉查找树.平衡二叉树.红黑树).图 ...
- 数据结构——二叉树的递归算法
二叉树的结构定义: typedef struct BiNode {TElemType data;struct BiNode *lchild;struct BiNode *rchild; }BiNode ...
- 数据结构——二叉树的层次遍历进阶
之前的一个博客 数据结构--二叉树的层次遍历看完这个,可以简单实现下面的问题 问题: 1.计算二叉树的最大宽度(二叉树的最大宽度是指二叉树所有层中结点个数的最大值. 2.用按层次顺序遍历二叉树的方法, ...
- 数据结构----二叉树叶子结点到根节点的高度计算
数据结构----二叉树叶子结点到根节点的高度计算 代码: #include<stdio.h> #include<stdlib.h> typedef struct bstTree ...
最新文章
- 3 css 奖品出现弹出动画_【技术】nuxt中引入wow和animate.css 页面随滚动条出现动画...
- R语言tidyr包separate()函数实战详解:一列裂变为多列
- 部落卫队pascal解题程序
- 在Unity中做一个淡入式的屏幕虚化
- ASP.NET MVC5 网站开发实践(二) Member区域 - 用户部分(2)用户登录、注销
- java内部格式_详解java内部类的访问格式和规则
- 公众号 -「前端攻略 开光篇」
- php做姓名隐藏,PHP只显示姓名首尾字符,隐藏中间字符并用*替换
- 【Java例题】2.5 温度转换
- java web 课程设计_关于Javaweb课程设计的心得体会.doc
- KingDZ 变菜鸟,每日一个C#小实例之---玩转鼠标
- 基于arduino的ESP32 学习笔记(四)基于AIDA64的电脑性能监控
- 正则html标签sublime,sublimetext 使用正则表达式匹配中文
- 10个重要的算法C语言实现源代码:拉格朗日,牛顿插值,高斯,龙贝格,牛顿迭代,牛顿-科特斯,雅克比,秦九昭,幂法,高斯塞德尔...
- 如何成为数据科学家_成为数据科学家
- 不改变图片分辨率,减少图片存储大小
- GOOGLE 手机定位厘米挑战赛选手提到的技巧、方法总结
- 【日常记录】CTF审查清单(linux)
- Java CsvReader 读取csv文件
- 工作五年,我该如何选择?
热门文章
- 基于 SquashFS 构建 Linux 可读写文件系统
- Fiddler URL域名转发
- vscode 插件摘抄
- C语言中函数的定义举例说明,C语言函数的定义与使用
- 前端路由vue-router
- Mybatis中limit用法与分页查询
- c语言里有队列函数没,C语言队列的实现 - osc_tf30cc36的个人空间 - OSCHINA - 中文开源技术交流社区...
- C++ 和 Java 函数互调
- liveplayer免费网页直播|点播播放器-页面动态多播放器添加代码示例
- 青岛计算机考研的学校,2015年计算机考研学校排名