内部排序->选择排序->树形选择排序
文字描述
树形选择排序又称锦标赛排序; 比如,在8个运动员中决出前3名至多需要11场比赛, 而不是7+6+5=18场比赛(它的前提是甲胜乙,乙胜丙,则甲必能胜丙)
首先对n个记录的关键字进行两两比较,然后在(n/2)个较小者之间再进行两两比较,直至选出最小关键字的记录为止,这个过程可用一颗有n个叶子结点的完全二叉树表示。关于完全二叉树的定义和与本排序算法用到的性质见附录1
示意图
算法分析
由于含n个叶子结点的完全二叉树的深度为[log2n]+1, 则在树形选择排序中,除了最小关键字外,每选择一个次小关键字仅需进行log2n次比较,因此它的时间复杂度为nlogn.。但是它需要的辅助空间为2*n-1。而且它在选择过程中,和"最大值"进行了多余的比较。 另外,该算法是不稳定的。
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/*
* double log2(double x); 以2为底的对数
* double ceil(double x); 取上整
* double floor(double x); 取下整
* double fabs(double x); 取绝对值
*/ #define DEBUG #define EQ(a, b) ((a) == (b))
#define LT(a, b) ((a) < (b))
#define LQ(a, b) ((a) <= (b)) #define MAXSIZE 100
#define INF 1000000
typedef int KeyType;
typedef char InfoType;
typedef struct{
KeyType key;
InfoType otherinfo;
}RedType; typedef struct{
RedType r[MAXSIZE+];
int length;
}SqList; void PrintList(SqList L){
int i = ;
printf("下标值:");
for(i=; i<=L.length; i++){
printf("[%d] ", i);
}
printf("\n关键字:");
for(i=; i<=L.length; i++){
if(EQ(L.r[i].key, INF)){
printf(" %-3c", '-');
}else{
printf(" %-3d", L.r[i].key);
}
}
printf("\n其他值:");
for(i=; i<=L.length; i++){
printf(" %-3c", L.r[i].otherinfo);
}
printf("\n\n");
return ;
} /*树形选择排序算法*/
void TreeSelectSort(SqList *L)
{
//为实现该排序所需的辅助树
SqList tree;
//辅助树的大小
tree.length = L->length- + L->length; tree.r[].otherinfo = '';
int i = , low = ;
//由后向前填充此树的叶子结点
for(i=; i<L->length; i++){
tree.r[tree.length-i] = L->r[L->length-i];
}
//由后向前填充此树的非叶子结点
for(i=(tree.length-L->length); i>=; i--){
tree.r[i] = (LT(tree.r[*i].key, tree.r[*i+].key)?tree.r[*i]:tree.r[*i+]);
}
//纪录当前辅助树的最小结点
RedType minred;
//记录最小结点在叶子结点中的下标值
int minindex = ;
while(low <= L->length){
minred = tree.r[];
#ifdef DEBUG
printf("第%d趟树形选择排序后,输出当前数最小值%d, %c\n", low, minred.key, minred.otherinfo);
PrintList(tree);
#endif
//不断移走最小结点
L->r[low++] = minred;
minindex = tree.length;
//找到最小值在辅助树叶子结点中的下标值
for(minindex=tree.length; (minindex>(tree.length-L->length)); minindex--){
if(EQ(tree.r[minindex].key, minred.key) && EQ(tree.r[minindex].otherinfo, minred.otherinfo)){
break;
}
}
//设置一个最大值标志,INF表示无穷大
tree.r[minindex].key = INF;
//重新调整此辅助树,使根结点关键字值最小
for(i=(minindex/); i>=; i/=){
tree.r[i] = (LT(tree.r[*i].key, tree.r[*i+].key)?tree.r[*i]:tree.r[*i+]);
}
}
#ifdef DEBUG
printf("按照树形选择排序后的原顺序表:\n");
PrintList(*L);
#endif
} int main(int argc, char *argv[])
{
if(argc < ){
return -;
}
SqList L;
int i = ;
for(i=; i<argc; i++){
if(i>MAXSIZE)
break;
L.r[i].key = atoi(argv[i]);
L.r[i].otherinfo = 'a'+i-;
}
L.length = (i-);
L.r[].key = ;
L.r[].otherinfo = '';
printf("输入数据:\n");
PrintList(L);
//对顺序表L作树形选择排序
TreeSelectSort(&L);
return ;
}
树形选择排序
运行
附录1 完全二叉树
定义:设二叉树深度为h,除第h层外,其他各层(1 ~ h-1)的结点数都达到最大个数,第h层所有的结点都集中在最左边,这就是完全二叉树。
性质:
1] 结点i (i>1)的双亲结点为i/2
2] 结点i的左孩子结点为2*i, 右孩子结点为2*i+1
3] 叶子结点数n0, 度为2(有左、右孩子结点)的结点数n2, 则n0 = n2+1
性质3]证明:
设n1为二叉树中度为1的结点数。因为二叉树中所有结点数的度均不大于2。所以二叉树的结点数n = n0 + n1 +n2 -- (1)。
又除根结点外,其余结点都有一个分支进入,设B为分支总数,则n=B+1。由于这些分支是由度为1或2的结点射出的,所以又有B=n1+2*n2,于是得n = B+1 = n1+2*n2+1 – (2)。
由(1)和(2)知, n0 = n2 +1
内部排序->选择排序->树形选择排序的更多相关文章
- 简单选择排序 Selection Sort 和树形选择排序 Tree Selection Sort
选择排序 Selection Sort 选择排序的基本思想是:每一趟在剩余未排序的若干记录中选取关键字最小的(也可以是最大的,本文中均考虑排升序)记录作为有序序列中下一个记录. 如第i趟选择排序就是在 ...
- 数据结构 - 树形选择排序 (tree selection sort) 具体解释 及 代码(C++)
树形选择排序 (tree selection sort) 具体解释 及 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 算法逻辑: 依据节点的大小, ...
- [译]async/await中使用阻塞式代码导致死锁 百万数据排序:优化的选择排序(堆排序)
[译]async/await中使用阻塞式代码导致死锁 这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的 ...
- Java常见排序算法之直接选择排序
在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...
- 用Python实现十大经典排序算法-插入、选择、快速、冒泡、归并等
本文来用图文的方式详细讲解了Python十大经典排序算法 —— 插入排序.选择排序.快速排序.冒泡排序.归并排序.希尔排序.插入排序.桶排序.基数排序.计数排序算法,想要学习的你们,继续阅读下去吧,如 ...
- php 实现冒泡算法排序、快速排序、选择排序,插入排序
许多人都说 算法是程序的核心,一个程序的好于差,关键是这个程序算法的优劣.作为一个初级phper,虽然很少接触到算法方面的东西 .但是对于冒泡排序,插入排序,选择排序,快速排序四种基本算法,我想还是要 ...
- 排序系列 之 简单选择排序及其改进算法 —— Java实现
简单选择排序算法: 基本思想: 在待排序数据中,选出最小的一个数与第一个位置的数交换:然后在剩下的数中选出最小的数与第二个数交换:依次类推,直至循环到只剩下两个数进行比较为止. 实例: 0.初始状态 ...
- 八大排序方法汇总(选择排序,插入排序-简单插入排序、shell排序,交换排序-冒泡排序、快速排序、堆排序,归并排序,计数排序)
2013-08-22 14:55:33 八大排序方法汇总(选择排序-简单选择排序.堆排序,插入排序-简单插入排序.shell排序,交换排序-冒泡排序.快速排序,归并排序,计数排序). 插入排序还可以和 ...
- [jQuery编程挑战]004 针对选择框词典式排序
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8&quo ...
随机推荐
- AtomicLong.lazySet 是如何工作的?
原文:http://www.quora.com/Java-programming-language/How-does-AtomicLong-lazySet-work Jackson Davis说:为一 ...
- CentOS下安装Vmtools
基本步骤差不多 [root@rd01 ~]# cd /media [root@rd01 ~]# ls -a [root@rd01 ~]# cp VMwareTools-5.5.1-19175.tar. ...
- Python_建造者模式
#!/usr/bin/python # -*- coding:utf-8 -*- #建造者基类 class PersonBuilder(): def BuildHead(self): pass def ...
- 编写具有临时root权限的应用
本文以dpkg为例进行演示 关于setuid具体原理可查阅<Unix高级环境编程>“进程控制”章节关于“设置用户id和设置组id”的介绍 1. 首先需要通过setuid(0),让程序获取临 ...
- HTML5超酷秒表动画 可暂停和重置秒表
关于HTML5和CSS3的时钟应用在之前我们已经分享过不少了,还有一些HTML5的日期选择应用.今天我们要分享一款基于HTML5和CSS3的圆盘秒表动画,秒表可以精确到0.001秒,并且可以在计时过程 ...
- swoole webSocket服务
socket.php <?php //创建websocket服务器对象,监听0.0.0.0:9502端口 $ws = ); //监听WebSocket连接打开事件 (刚打开的时候会给客户端发送 ...
- 解决VisualStudio无法调试的问题
方法1 方法2
- JavaScript 之 function函数及参数arguments
JavaScript用function关键字声明函数,可以用return返回值,也可以没有返回值. 建议:要么统一有返回值,要么统一都没有返回值,这样调试代码方便. 函数定义格式: function ...
- linux命令学习(5):pwd命令
Linux中用 pwd 命令来查看”当前工作目录“的完整路径. 简单得说,每当你在终端进行操作时,你都会有一个当前工作目录. 在不太确定当前位置时,就会使用pwd来判定当前目录在文件系统内的确切位置. ...
- 7.13python多进程
所以引入了 多进程*(异步) 处理效率高 #!/usr/bin/env python #!--*--coding:utf-8 --*-- #!@Time :2018/7/13 19:26 #! ...