二叉树

  • 一.树
    • 1.1树的概念
    • 1.2结构
    • 1.3相关的概念
    • 1.4树的表示方法
  • 二.二叉树
    • 2.1二叉树的概念
    • 2.2二叉树的存储结构
    • 2.3二叉树的性质
    • 2.4堆
      • 2.4.1概念及性质
      • 2.4.2堆的性质
      • 2.4.3堆的实现
      • 2.4.4堆的应用
    • 2.5二叉树的遍历
    • 2.6二叉树中的方法及其实现

一.树

1.1树的概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成的具有层次关系的集合。

1.2结构

  • 有一个特殊的结点,称为根结点,根节点没有前驱结点
  • 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i<=
    m)又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继
  • 树是递归定义的
  • 子树是不相交的
  • 除了根节点外,每个节点有且仅有一个父节点,其一棵N个节点的树有N-1条边。

1.3相关的概念

  • 节点的度:一个节点含有的子树的个数称为该节点的度
  • 叶节点或终端节点:度为0的节点称为叶节点
  • 非终端节点或分支节点:度不为0的节点
  • 树的度:一棵树中,最大的节点的度称为树的度
  • 节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推
  • 树的高度或深度:树中节点的最大层次
  • 森林:由m(m>0)棵互不相交的树的集合称为森林

1.4树的表示方法

  • 孩子表示法

在该节点中表示出其孩子结点即可(优点,找孩子结点方标,找双亲结点不方便)

  • 双亲表示法

在该结点中表示出双亲结点即可(找双亲结点方便,找孩子结点不方便)

//孩子表示法
typedef struct int DType;
typedef struct node{DType data;struct node* right;struct node* left;
}node;
  • 孩子双亲表示法

    孩子兄弟表示法
    树结构相对线性表就比较复杂了,要存储表示起来就比较麻烦了,常用的是孩子兄弟表示法。

二.二叉树

2.1二叉树的概念

一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。
二叉树的特点:

  1. 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。
  2. 二叉树的子树有左右之分,其子树的次序不能颠倒。

特殊的二叉树:

  1. 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
  2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

2.2二叉树的存储结构

二叉树可以使用两种存储结构:顺序结构和链式结构。
顺序存储:
当二叉树满足完全二叉树时采用顺序存储,它一般采用数组进行存储,,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储。(二叉树在物理存储上是一个数组,在逻辑上是一个二叉树)

链式存储:
二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链。

2.3二叉树的性质

  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).。(ps:Log2(n+1)是log以2为底,n+1为对数)
  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
    若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
    若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
    若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

2.4堆

2.4.1概念及性质

如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

2.4.2堆的性质

  • 堆顶元素一定是最大或者最小元素
  • 他是一个完全二叉树
  • 双亲结点比任意结点要大或者小

2.4.3堆的实现

(完整代码自取–>包含小堆,大堆实现)

  1. 堆向下调整算法

让完全二叉树满足堆特点,需要将二叉树的数组进行调整,进行双亲结点和孩子结点进行比较,然后进行交换。
在这里要注意的几点:

  • 结点编号:
    左孩子–>2i+1
    右孩子–>2i+2(给出父节点i)
    双亲结点–>(i-1)/2(给出孩子节点)
  • 父节点可能会没有右孩子
void adjust(DType array[], int size, int parent){//默认让child标记左孩子,因为parent可能不存在右孩子int child = parent * 2 + 1;while (child<size&&array[child]<array[parent]){//右孩子存在的情况:if (child<size&&array[child + 1]<array[child]) //要注意&&两边的先后次序,如果比较左右孩子放在前面,会造成访问越界{child += 1;//让child标记右孩子}//检测parent是否满足情况if (array[child]<array[parent]){swap(&array[child], &array[parent]);//较大的双亲和孩子交换后,可能会导致子树不满足parent = child;child = parent * 2 + 1;}else{//如果双亲比孩子节点还小return;}}
}
  1. 堆的初始化
//初始化
heap* heapInit(heap* hp, DType* array, int size){assert(hp);int lastnotleaf = 0;hp->array = (DType*)malloc(sizeof(DType)*size);if (NULL == hp->array){return NULL;}   hp->capacity = size;//memcpy(hp->array, array, sizeof(sizeof(DType)*size));//以字节为准进行拷贝,大小为(sizeof(DType)*capa)for (int i = 0; i < size; i++){hp->array[i] = array[i];}hp->size = size;//找到非叶子结点lastnotleaf = ((size - 1) - 1) / 2;//从该结点位置逐个往前直到根for (int root = lastnotleaf; root >= 0; root--){adjust(hp->array, size, root);}return hp;
}
  1. 堆的插入

在进行对的插入时,我们要进行一下几个步骤:

  • 先将插入元素直接插入堆尾
  • 对数进行调整,知道满足堆的特性(找到插入结点的双亲进行比较)
//插入
//插入
void heapInsert(heap* hp, DType data){//首先确定堆是否已满if (hp->size == hp->capacity){//已满先进行扩容hp->array = (DType*)realloc(hp->array,sizeof(DType)*(hp->capacity)*2);if (NULL == hp->array){assert(0);return;}hp->capacity *= 2;}//先将data插入堆中hp->array[hp->size++] = data;//然后对插入后的孩子节点与其父节点进行比较,调换adjustup(hp->array, hp->size);
}
void adjustup(DType* array,int size){int child = size-1;int parent = (child - 1) / 2;while (child){if (array[child] < array[parent]){swap(&array[child], &array[parent]);child = parent;parent = (child - 1) / 2;}else return;}
}
  1. 堆的删除

堆的删除进行的步骤:

  • 交换堆顶元素和堆尾元素
  • 进行调整堆顶元素的位置
//删除
void heapdel(heap* hp){//判断堆是否为空if (heapempty(hp)) return;//交换堆顶和堆尾元素swap(&hp->array[0], &hp->array[hp->size - 1]);//有效个数-1hp->size -= 1;//对现在的二叉树进行重新排序,再次成堆adjust(hp->array, hp->size, 0);
}
  1. 其余的一些方法
//获取堆顶元素
DType heaptopdata(heap* hp){assert(!heapempty(hp));return hp->array[0];
}
//检测是否为空
int heapempty(heap* hp){assert(hp);return 0 == hp->size;
}
//获取堆里有效元素的个数
int heapsize(heap* hp){assert(hp);return hp->size;
}
//对的销毁
void heapdestory(heap* hp){assert(hp);if (hp->array){free(hp->array);hp->array = NULL;hp->capacity = 0;hp->size = 0;}
}
void swap(DType* left, DType* right){int temp = *left;*left = *right;*right = temp;
}

2.4.4堆的应用

  • 堆排序–假设我们排升序

1.建堆(在排序中升序选择–>大堆, 降序选择–>小堆)
2.排序–>利用堆删除的思想进行排序
例如下图:我们所求升序,因此在建堆的时候先建成大堆,保证堆顶值最大,然后一次将堆顶元素与堆为元素进行交换,使得最大元素在物理存储上即在数组的最后一位,然后对剩下的重新进行向下调整,使得每次都能将剩下的最大数值放到剩下此时空间的末位,最后得到升序数组(的到降序数组与其原理类似)。

降序:利用的是小堆

int less(DType left, DType right){//大堆return left < right;
}
//堆排序-->降序
void sort(heap* hp){if (heapempty(hp)) return;int size = hp->size-1;int count = 0;while (size){if (hp->array[0] < hp->array[size]){heapdel(hp);count++;}else{size--;}}hp->size += count;
}

升序:利用的是大堆

int less(DType left, DType right){//大堆return left > right;
}
//堆排序-->降序
void sort(heap* hp){if (heapempty(hp)) return;int size = hp->size-1;int count = 0;while (size){if (hp->array[0] > hp->array[size]){heapdel(hp);count++;}else{size--;}}hp->size += count;
}

  • TOP-K问题(找最小的前K个)

1.方法一–排序(O(NlogN)),但是在数据量比较大的情况下使用不了。
2.方法二–用堆处理
步骤一:用前K个元素建堆(求前K个最大的建小堆;求前K个最小的建大堆)
步骤二:(求最大的前K个)使用剩余的N-K元素一次与堆顶进行比较,如果比堆顶大,则元素进行替换,然后再进行堆的重新排序(因为我们此事件的是小堆,每次将N-K的元素与堆顶进行比较的时候,都相当与与队中最小的比较,也就是剔除堆中最小的元素)
输出前K个最大值:

//TOP-K
void TOP_K(heap* hp, int k, int* array,int size){//建前K给元素的小堆heapInit(hp,array,k,less);int dex = k;while (dex<size){if (array[dex]>hp->array[0]){hp->array[0] = array[dex];adjust(hp,0);dex++;}else{dex++;}}
}

输出前K个最小值:

void TOP_K(heap* hp, int k, int* array,int size){//建前K给元素的大堆heapInit(hp,array,k,less);int dex = k;while (dex<size){if (array[dex]《hp->array[0]){hp->array[0] = array[dex];adjust(hp,0);dex++;}else{dex++;}}
}

2.5二叉树的遍历

2.6二叉树中的方法及其实现

(链接)

二叉树(1.二叉树的概念堆)相关推荐

  1. 数据结构(3) 第三天 栈的应用:就近匹配/中缀表达式转后缀表达式 、树/二叉树的概念、二叉树的递归与非递归遍历(DLR LDR LRD)、递归求叶子节点数目/二叉树高度/二叉树拷贝和释放...

    01 上节课回顾 受限的线性表 栈和队列的链式存储其实就是链表 但是不能任意操作 所以叫受限的线性表 02 栈的应用_就近匹配 案例1就近匹配: #include <stdio.h> in ...

  2. 再谈二叉树(二叉树概念,二叉树的性质,二叉树的存储结构)

    树的概念 树的概念 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合.把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的.它具有以下的特点 ...

  3. 关于树和二叉树的一些基本概念,基本名词解释。

    二叉树的概念 概念 一棵二叉树是结点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树 的二叉树组成. 二叉树的特点: 每个结点最多有两棵子树,即二叉树不存在度大于2的结点 ...

  4. 【数据结构之二叉树】——二叉树的概念及结构,特殊的二叉树和二叉树性质

    文章目录 一.二叉树的概念及结构 1.概念 2.现实中的二叉树 3. 特殊的二叉树: 3.二叉树的性质 二.二叉树练习题 总结 一.二叉树的概念及结构 1.概念 一棵二叉树是结点的一个有限集合,该集合 ...

  5. 二叉树(BinaryTree)和堆(Heap)的知识点整理

    一.二叉树 二叉树(Binary tree)是每个节点最多只有两个分支(即不存在分支度大于 2 的节点)的树结构. 二叉树又分为满二叉树,完全二叉树,平衡二叉树. 1.满二叉树 一个二叉树,如果每一个 ...

  6. 二叉树(一)概念及其三种遍历方式实现

    目录 1. 树型结构 1.1 概念 1.2 概念(重要) 1.3 树的表示形式(了解) 1.4 树的应用 2. 二叉树(重点) 2.1 概念 二叉树的特点: 2.2 二叉树的基本形态 2.3 两种特殊 ...

  7. c#二叉树 取叶子节点个数_数据结构第四章:树与二叉树(二叉树的概念、性质、特殊二叉树)...

    第四章:树与二叉树(二叉树的逻辑结构) 1.二叉树 二叉树是树结构的一种,故二叉树也是逻辑结构. 二叉树:二叉树是n(n≥0)个结点的有限集合. · 1)n=0时,二叉树为空; · 2)n>0时 ...

  8. 二叉树的基本特性和二叉树的几种基本操作的机制_深入理解二叉树01 二叉树基础

    数据结构是所有的程序员就业过程中无法回避的知识,最近在回顾数据结构的内容,因此会不定期的推出一些数据结构的文章,分享自己的笔记. 树是数据结构中的重点,由于二叉树又是树中的重中之重.二叉树的应用也非常 ...

  9. 【数据结构Note5】- 树和二叉树(知识点超细大全-涵盖常见算法 排序二叉树 线索二叉树 平衡二叉树 哈夫曼树)

    文章目录 5.1 树和二叉树引入 5.1.1 树的概念 5.1.2 树的表示 5.1.3 树中基本术语 5.2 二叉树 5.2.1 概念 5.2.2 二叉树的性质 5.2.3 特殊的二叉树 5.2.4 ...

最新文章

  1. 我是如何根据豆瓣api来理解Restful API设计的
  2. FZOJ 2014年11月份月赛 ytaaa(dp + RMQ)
  3. HTTP Server Error 500 内部服务器错误
  4. Java中已检查和未检查的异常
  5. python解析html xml最好的模块_python中处理xml的模块哪个好?
  6. django1.11 mysql配置_Mysql没有使用python3.6与Django 1.11.7连接
  7. java mysql大小写_MySQL大小写敏感的解决方案
  8. SQL Server Always On可用性组中的Windows故障转移群集仲裁模式
  9. C++之编写dll库
  10. coffeescript java 执行_CoffeeScript—面向对象
  11. 虚拟机连接本地数据库
  12. 校企同游快乐工作——湖南工程职院美和易思教师开展素质拓展活动
  13. 重要通知丨涂鸦安防SaaS产品 新版本发布!
  14. 什么语言最适合做 GUI?
  15. Python-求一元二次方程ax^2+bx+c=0的解
  16. Excel如何永久去除“受保护视图”的打开提醒?
  17. 【AI理论学习】多模态介绍及当前研究方向
  18. ElasticSearch之SpringData集成版本差异
  19. 便利贴--17{移动端滑动模块}
  20. 《2018人工智能芯片技术白皮书》发布

热门文章

  1. 叶子的离开,是风的追逐,还是树的不留恋?
  2. 导出pdf内容包换特殊符号,或转行符号等解决方法
  3. AM5728 linux内核编译方法
  4. 如何实现开发一个企业认证开发版微信服务号的详细步骤
  5. 能哄老婆睡觉的小故事
  6. 呼叫中心和电话营销系统相关知识--中继线路
  7. 随笔2022.12.6
  8. 计算机网络ip地址在哪,w7的ip地址在哪?小编教你怎么查看
  9. 计算机主机上有几个按钮,电脑键盘各个按键有哪些作用 电脑键盘各个按键作用介绍...
  10. 就业喜报|最高薪资15K,平均7216元,这个双十一不做“吃圭人”!