[排序算法] 树形选择排序 (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来记住他的位置, 接着第二次比较,前面"后一个元素"现变成了"前一个元素& ...
随机推荐
- InnoDB_锁总结
1. 查询会对资源添加共享锁 加了共享锁的资源不可以被修改:但可以被查询(也是会在资源上再加共享锁) 2. 数据修改会对资源添加排他锁 加了排他锁的资源只能被持有这个排他锁的事务读取和修改,其他事务读 ...
- sedona(Geospark)读取csv
package com.grady.sedona import org.apache.sedona.sql.utils.SedonaSQLRegistrator import org.apache.s ...
- MySQL半同步复制源码解析
今天 DBA 同事问了一个问题,MySQL在半同步复制的场景下,当关闭从节点时使得从节点的数量 < rpl_semi_sync_master_wait_for_slave_count时,show ...
- 2021年1月-第02阶段-前端基础-HTML+CSS阶段-Day01
HTML5 第一天 一.什么是 HTML5 1.HTML5 的概念与定义 定义:HTML5 定义了 HTML 标准的最新版本,是对 HTML 的第五次重大修改,号称下一代的 HTML 两个概念: 是一 ...
- 第六章:Django 综合篇 - 11:分页 Paginator
分页功能是几乎所有的网站上都需要提供的功能,当你要展示的条目比较多时,必须进行分页,不但能减小数据库读取数据压力,也有利于用户浏览. Django又很贴心的为我们提供了一个Paginator分页工具, ...
- MySQL读写分离之——ProxySQL
文章转载自:https://blog.csdn.net/u012280685/article/details/113520692?spm=1001.2014.3001.5501 实现一个简单的读写分离 ...
- MySQL 数据更新过程
文章转载自:https://mp.weixin.qq.com/s?__biz=MzI1MDgwNzQ1MQ==&mid=2247486441&idx=1&sn=fcf93709 ...
- flutter系列之:查询设备信息的利器:MediaQuery
目录 简介 MediaQuery详解 MediaQuery的属性 MediaQuery的构造函数 MediaQuery的使用 总结 简介 移动的开发中,大家可能最头疼的就是不同设备的规格了,现在设备这 ...
- 货币转换I
A=input() if A[0] in ['U','u']: RMB=(eval(A[3:]))*6.78 print("RMB{:.2f}".format(RMB)) else ...
- C#-10 事件
一 发布者和订阅者 很多时候都有这种需求,当一个特定的程序事件发生时,程序的其他部分可以得到该事件已经发生的通知. 发布者/订阅者模式可以满足这种需求. 发布者:发布某个事件的类或结构,其他类可以在该 ...