[排序算法] 树形选择排序 (C++)
树形选择排序解释
树形选择排序 又称为锦标赛排序,其实理解起来很简单。
数组的 n 个元素就好像在进行锦标赛一样,每一轮小比赛每两个一组决出胜负(比较谁更小)。
再将每一轮的胜者每两个一组进行小比赛,直到最后决出唯一的胜者(即当前最小元素)。很明显,锦标赛构成图的形状就是一个满二叉树捏。
每一次锦标赛决出的最终胜者(最小元素),我们要将其退出比赛,即放到原数组中。
重复上述操作,n 次锦标赛,即可完成排序。
那么具体如何实现呢?
我们需要用定义一个 tree[] 数组用来存储这个满二叉树。
首先我们需要录入叶子节点,也就是我们需要排序的数组中的所有元素。
然后根据二叉树在数组中的表示方法,我们知道 若二叉树某个节点的下标为 i,可得其左孩子节点的下标为 2 * i + 1,右孩子节点下标为 2 * i + 2。
由此通过现有的叶子节点,可以得到其父节点的值,形象地说就是可以得到两个叶子节点的决胜者,即较小值。
当每次得到当前最小值,我们需要定义一个 minindex 在 tree[] 中寻找到当前这个最小值的索引,并将其置 MAX(这样就好像是它退出锦标赛了)
树形选择排序动态演示
我们以 [1, 4, 2, 3] 为例进行动态演示
第一次锦标赛得到决胜者
第二次锦标赛得到决胜者
第三次锦标赛得到决胜者
第四次锦标赛得到决胜者
树形选择排序时间复杂度
每次决出当前最小值,需要进行 log2n 次比较,总共需要进行 n 次锦标赛,所以时间复杂度
树形选择排序核心代码
void TreeSelectSort(int a[], int n){
int nodesum = n * 2 - 1; //满二叉树节点总数
int *tree = new int[nodesum];
/* 录入叶子节点 */
for(int i = n - 1, j = 0; i >= 0; i--, j++)
tree[nodesum - j - 1] = a[i];
/* 录入非叶子节点 */
for(int i = nodesum - n - 1; i >= 0; i--)
tree[i] = tree[2 * i + 1] < tree[2 * i + 2] ? tree[2 * i + 1] : tree[2 * i + 2];
/* 每次找出最小元素并复制到原数组 */
int k = 0, minindex = -1;
while(k < n){
int min = tree[0]; //当前的树根节点值即为最小元素
a[k++] = min;
minindex = nodesum - 1;
/* 从最后叶子节点开始,找到最小值位置,并将其置MAX */
while(tree[minindex] != min)
minindex--;
tree[minindex] = INT_MAX;
/* 若此节点有父节点,将其兄弟节点值提升到父节点位置 */
while(minindex > 0){
if(minindex % 2 == 1){
//该节点为左节点
tree[(minindex - 1)/2] = tree[minindex] < tree[minindex + 1] ? tree[minindex] : tree[minindex + 1];
minindex = (minindex - 1)/2;
}else{
//该节点为右节点
tree[minindex/2 - 1] = tree[minindex] < tree[minindex - 1] ? tree[minindex] : tree[minindex - 1];
minindex = minindex/2 - 1;
}
}
}
delete[] tree;
}
完整程序源代码
#include<iostream>
#include<ctime>
using namespace std;
void TreeSelectSort(int a[], int n){
int nodesum = n * 2 - 1; //满二叉树节点总数
int *tree = new int[nodesum];
/* 录入叶子节点 */
for(int i = n - 1, j = 0; i >= 0; i--, j++)
tree[nodesum - j - 1] = a[i];
/* 录入非叶子节点 */
for(int i = nodesum - n - 1; i >= 0; i--)
tree[i] = tree[2 * i + 1] < tree[2 * i + 2] ? tree[2 * i + 1] : tree[2 * i + 2];
/* 每次找出最小元素并复制到原数组 */
int k = 0, minindex = -1;
while(k < n){
int min = tree[0]; //当前的树根节点值即为最小元素
a[k++] = min;
minindex = nodesum - 1;
/* 从最后叶子节点开始,找到最小值位置,并将其置MAX */
while(tree[minindex] != min)
minindex--;
tree[minindex] = INT_MAX;
/* 若此节点有父节点,将其兄弟节点值提升到父节点位置 */
while(minindex > 0){
if(minindex % 2 == 1){
//该节点为左节点
tree[(minindex - 1)/2] = tree[minindex] < tree[minindex + 1] ? tree[minindex] : tree[minindex + 1];
minindex = (minindex - 1)/2;
}else{
//该节点为右节点
tree[minindex/2 - 1] = tree[minindex] < tree[minindex - 1] ? tree[minindex] : tree[minindex - 1];
minindex = minindex/2 - 1;
}
}
}
delete[] tree;
}
void show(int *a, int n){
for(int i = 0; i < n; i++)
cout<<*(a + i)<<" ";
cout<<endl;
}
main(){
int a[50];
srand((int)time(0));
int k = 0;
while(k < 50)
a[k++] = rand() % 100 + 1;
show(a, 50);
TreeSelectSort(a, 50);
cout<<endl<<endl;
show(a, 50);
}
程序运行结果图
[排序算法] 树形选择排序 (C++)的更多相关文章
- Python排序算法之选择排序定义与用法示例
Python排序算法之选择排序定义与用法示例 这篇文章主要介绍了Python排序算法之选择排序定义与用法,简单描述了选择排序的功能.原理,并结合实例形式分析了Python定义与使用选择排序的相关操作技 ...
- 八大排序算法~简单选择排序【记录下标k变量的作用】
八大排序算法~简单选择排序[记录下标k变量的作用] 1,思想:打擂台法,数组中的前n-1个元素依次上擂台"装嫩",后边的元素一个挨着一个不服,一个一个上去换掉它 2,优化:通过记录 ...
- 排序算法总结------选择排序 ---javascript描述
每当面试时避不可少谈论的话题是排序算法,上次面试时被问到写排序算法,然后脑袋一懵不会写,狠狠的被面试官鄙视了一番,问我是不是第一次参加面试,怎么可以连排序算法都不会呢?不过当时确实是第一次去面试,以此 ...
- 八大排序算法之四选择排序—堆排序(Heap Sort)
堆排序是一种树形选择排序,是对直接选择排序的有效改进. 基本思想: 堆的定义如下:具有n个元素的序列(k1,k2,...,kn),当且仅当满足 时称之为堆.由堆的定义可以看出,堆顶元素(即第一个元素) ...
- 【DS】排序算法之选择排序(Selection Sort)
一.算法思想 选择排序是一种简单直观的排序算法.它的工作原理如下: 1)将序列分成两部分,前半部分是已经排序的序列,后半部分是未排序的序列: 2)在未排序序列中找到最小(大)元素,放到已排序序列的末尾 ...
- 八大排序算法之三选择排序—简单选择排序(Simple Selection Sort)
基本思想: 在要排序的一组数中,选出最小(或者最大)的一个数与第1个位置的数交换:然后在剩下的数当中再找最小(或者最大)的与第2个位置的数交换,依次类推,直到第n-1个元素(倒数第二个数)和第n个元素 ...
- 常用排序算法之——选择排序(C语言+VC6.0平台)
选择排序是另一种经典排序算法,核心思想是:在一趟找最小(大)数的过程中,先假设待排数据中的第一个数据即为最小(大)数据,然后循环将其他数据与该数据比较,每次比较时若小于该数据则让新数据成为最小(大)数 ...
- Java排序算法之选择排序
一.算法原理 简单选择排序的基本思想:给定数组:int[] arr={里面n个数据}:第1趟排序,在待排序数据arr[1]~arr[n-1]中选出最小的数据,将它与arrr[0]交换:第2趟,在待排序 ...
- 【排序算法】选择排序(Selection sort)
0. 说明 选择排序(Selection sort)是一种简单直观的排序算法. 它的工作原理如下. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最 ...
- 我的Java开发学习之旅------>Java经典排序算法之选择排序
一.算法原理 对比数组中前一个元素跟后一个元素的大小,如果后面的元素比前面的元素小则用一个变量k来记住他的位置, 接着第二次比较,前面"后一个元素"现变成了"前一个元素& ...
随机推荐
- Java开发学习(三十)----Maven聚合和继承解析
一.聚合 分模块开发后,需要将这四个项目都安装到本地仓库,目前我们只能通过项目Maven面板的install来安装,并且需要安装四个,如果我们的项目足够多,那么一个个安装起来还是比较麻烦的 如果四个项 ...
- 利用rpmbuild 打包可执行文件和链接库生成rpm 包
Background: Background: 遇到一个打包可执行程序和链接库生成rpm 包的需求,查遍了很多网站的资料,现在整理下解决方案. 前期参考的是这篇帖子: https://codeante ...
- 详解字符编码与 Unicode
人类交流使用 A.B.C.中 等字符,但计算机只认识 0 和 1.因此,就需要将人类的字符,转换成计算机认识的二进制编码.这个过程就是字符编码. ASCII 最简单.常用的字符编码就是 ASCII(A ...
- 前端必读2.0:如何在React 中使用SpreadJS导入和导出 Excel 文件
最近我们公司接到一个客户的需求,要求为正在开发的项目加个功能.项目的前端使用的是React,客户想添加具备Excel 导入/导出功能的电子表格模块. 经过几个小时的原型构建后,技术团队确认所有客户需求 ...
- Django 连接数据库 MySQL
一.Django 连接 MySQL 修改 settings.py 文件 # 默认用的是sqlite3 # Database # https://docs.djangoproject.com/en/4. ...
- ProxySQL(2):初试读写分离
文章转载自:https://www.cnblogs.com/f-ck-need-u/p/9278839.html 实现一个简单的读写分离 这里通过一个简单的示例实现ProxySQL的读写分离功能,算是 ...
- 修复 Elasticsearch 集群的常见错误和问题
文章转载自:https://mp.weixin.qq.com/s/8nWV5b8bJyTLqSv62JdcAw 第一篇:Elasticsearch 磁盘使用率超过警戒水位线 从磁盘常见错误说下去 当客 ...
- krew插件安装
概念 Krew是kubectl插件的包管理工具.借助Krew,可以轻松地使用kubectl plugin:发现插件.安装和管理插件.使用类似apt.dnf或者brew. 对于kubectl用户:kre ...
- .NET 反向代理 YARP 自定义配置提供程序(Configuration Providers)
介绍 基本 Yarp 示例显示从 appsettings.json 加载的代理配置.相反,代理配置可以从您选择的源以编程方式加载.您可以通过提供几个实现 IProxyConfigProvider 和 ...
- 【可视化大屏教程】用Python开发智慧城市数据分析大屏!
目录 一.开发背景 二.讲解代码 2.1 大标题+背景图 2.2 各区县交通事故统计图-系列柱形图 2.3 图书馆建设率-水球图 2.4 当年城市空气质量aqi指数-面积图 2.5 近7年人均生产总值 ...