内部排序->选择排序->树形选择排序
文字描述
树形选择排序又称锦标赛排序; 比如,在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 ...
随机推荐
- 【ZooKeeper】ZooKeeper入门流水记
单机模式 下载zookeeper的包 wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.9/zookeeper-3.4.9.ta ...
- d3实现的力向导图
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- [转](OS 10038)在一个非套接字上尝试了一个操作 的解决办法
原文: http://blog.csdn.net/zooop/article/details/47170885 可能是安装了某些程序修改了Winsock,使用netsh winsock reset 命 ...
- 【emWin】例程三十:窗口对象——Multiedit
简介: 本例程介绍MULTIEDIT的使用方法通过MULTIEDIT 小工具可编辑多行文本.它既 可以被用作简单的文本编辑器,也可以用来显示静态文本.该小工具支持带滚动条 和不带滚动条的滚动 触摸校准 ...
- 聊聊模板方法模式,装饰器模式以及AOP
在软件系统设计的时候,我们需要把一个大的系统按照业务功能进行拆分,做到高内聚.低耦合. 但是呢,拆分之后会产生一些通用性的东西,比如日志,安全,事务,性能统计等,这些非功能性需求,横跨多个模块.最lo ...
- 安卓程序代写 网上程序代写[原]Android中的回调Callback
回调就是外部设置一个方法给一个对象, 这个对象可以执行外部设置的方法, 通常这个方法是定义在接口中的抽象方法, 外部设置的时候直接设置这个接口对象即可. 1. 如何定义一个回调 a. 定义接口 : 在 ...
- Java如何获取URL的部分?
在Java编程中,如何获取URL的一部分? 以下示例显示了如何通过net.URL类的url.getProtocol()和url.getFile()方法等获取URL的部分. package com.yi ...
- SpringMVC Jsp include 错误404 不显示页面
一.问题描述: 1. 新建了taglibs.jsp存放jstl标签库和 jsp建站基本变量ctx 和basPath 如下 (位置WEB-INF\common) <%@ page import= ...
- 解决java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone
使用spring boot整合MySQL时一直报 java.sql.SQLException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecog ...
- 【Oracle-PLsql】使用存储过程,利用table集合类型开发复杂业务报表
在一般的项目中,都需要开发一些报表,少则几个字段,多则几十个字段,需要关联的表可能多达十几.几十张表,如果想要使用一个SQL语句将这几十张表关联起来 查询所需要的字段,当你听到这里的时候,你的脑子可能 ...