内部排序->其它->地址排序(地址重排算法)
文字描述
当每个记录所占空间较多,即每个记录存放的除关键字外的附加信息太大时,移动记录的时间耗费太大。此时,就可以像表插入排序、链式基数排序,以修改指针代替移动记录。但是有的排序方法,如快速排序和堆排序,无法实现表排序。这种情况下就可以进行“地址排序”,即另设一个地址向量指示相应记录的位置;同时在排序过程中不移动记录而移动记录地址向量中相应分量的内容。见示意图,(b)是排序结束后的地址向量,地址相连adr[1,…,8]中的值表示排序后的记录的次序,r[adr[1]]为最小记录,r[adr[8]]为最大记录。
如果需要的话,可根据adr的值重排记录的物理位置。重排算法如下:
比如要根据示意图中的(b)中地址向量重排原记录的话,由于(b)中的adr[1]=6, 则在暂存R(49)后,需要将R(13)从r[6]的位置移动到r[1]。又因为adr[6]=2,则将R(65)从r[2]的位置移至r[6]的位置。同理,将R(27)移至r[2]的位置,此时因adr[4]=1,则之前暂存的R(49)应该放在r[4]的位置上。至此完成一个调整记录位置的小循环,此小循环完成后的记录及地址向量的状态如示意图(c)所示。
示意图

算法分析
地址排序不能算是独立的算法,只是在之前讨论的内部排序算法中,另设一个地址向量,用移动地址向量中的分量值代替移动记录而已。
地址重排算法中,因为每个小循环要暂存一个记录,所以辅助空间为1
地址重排算法中,除需要暂存的记录外,所有记录均一次到位。而每个小循环至少移动两个记录,则这样的小循环最多n/2个,所以重排算法中至多移动记录[3n/2]次,其时间复杂度为n。
代码实现
#include <stdio.h>
#include <stdlib.h> #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 adr[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地址值:");
for(i=; i<=L.length; i++){
printf(" %-3d", L.adr[i]);
}
printf("\n\n");
return ;
} //堆采用顺序存储表示
typedef SqList HeapType; /*
*已知H->r[s,...,m]中记录的关键字除H->r[s].key之外均满足的定义
*本函数调整H-r[s]的关键字,使H->r[s,...,m]成为一个大顶堆(对其中
*记录的关键字而言)
*/
void HeapAdjust(HeapType *H, int s, int m)
{
// RedType rc = H->r[s];
RedType rc = H->r[H->adr[s]];
int rc_adr = H->adr[s];
int j = ;
//沿key较大的孩子结点向下筛选
for(j=*s; j<=m; j*=){
//j为key较大的纪录的下标
if(j<m && LT(H->r[H->adr[j]].key, H->r[H->adr[j+]].key))
j+=;
//rc应该插入位置s上
if(!LT(rc.key, H->r[H->adr[j]].key))
break;
H->adr[s] = H->adr[j];
s = j;
}
//插入
H->adr[s] = rc_adr;
} /*
* 对顺序表H进行堆排序
*/
void HeapSort(HeapType *H)
{
#ifdef DEBUG
printf("开始堆排序,和之前的堆排序不同之处在于,移动地址向量代替移动记录。\n");
#endif
int i = ;
//把H->r[1,...,H->length]建成大顶堆
for(i=H->length/; i>=; i--){
HeapAdjust(H, i, H->length);
}
#ifdef DEBUG
printf("由一个无序序列建成一个初始大顶堆:\n");
PrintList(*H);
#endif
int tmp;
for(i=H->length; i>; i--){
//将堆顶记录和当前未经排序子序列H->r[1,...,i]中最后一个记录相互交换
tmp = H->adr[];
H->adr[] = H->adr[i];
H->adr[i] = tmp;
//将H->r[1,...,i-1]重新调整为大顶堆
HeapAdjust(H, , i-);
#ifdef DEBUG
printf("调整1至%d的元素,使其成为大顶堆:\n", i-);
PrintList(*H);
#endif
}
} /*
* adr给出顺序表H的有序次序,即L->r[adr[i]]是第i小的记录
* 本算法按adr重排H,使其有序
*/
void Rearrange(HeapType *H, int adr[])
{
int i = , j =, k = ;
for(i=; i<=H->length; i++){
if(adr[i] != i){
//暂存记录H->r[i]
H->r[] = H->r[i];
j = i;
//调整L->r[adr[j]]的记录到位直到adr[j] == i为止
while(adr[j] != i){
k = adr[j];
H->r[j] = H->r[k];
adr[j] = j;
j = k;
}
//记录到序
H->r[j] = H->r[];
adr[j] = j;
#ifdef DEBUG
printf("第%d躺调整:\n", i);
PrintList(*H);
#endif
}
}
} int main(int argc, char *argv[])
{
if(argc < ){
return -;
}
HeapType H;
int i = ;
for(i=; i<argc; i++){
if(i>MAXSIZE)
break;
H.r[i].key = atoi(argv[i]);
H.r[i].otherinfo = 'a'+i-;
H.adr[i] = i;
}
H.length = (i-);
H.r[].key = H.adr[] = ;
H.r[].otherinfo = '';
printf("输入数据:\n");
PrintList(H);
//对顺序表H作堆排序
HeapSort(&H);
#ifdef DEBUG
printf("对排序后的顺序表按照地址向量重新调整记录位置,使其有序\n");
#endif
Rearrange(&H, H.adr);
PrintList(H);
return ;
}
堆排序(采用地址排序)_地址重排算法
运行


内部排序->其它->地址排序(地址重排算法)的更多相关文章
- JavaScript按IP地址排序
JavaScript按IP地址列表排序,主要思路就是分割每个点号部分,然后ip1和ip2分别对不够三位数的进行补0操作,然后转换为数字类型进行一一比较. 上代码: 正序: var arr=[ {ip: ...
- python对ip地址排序、对列表进行去重
一:使用python对ip地址排序所用代码示例一: import socket iplist = ['10.5.11.1','192.168.1.33','10.5.2.4','10.5.1.3',' ...
- 算法与数据结构(十三) 冒泡排序、插入排序、希尔排序、选择排序(Swift3.0版)
本篇博客中的代码实现依然采用Swift3.0来实现.在前几篇博客连续的介绍了关于查找的相关内容, 大约包括线性数据结构的顺序查找.折半查找.插值查找.Fibonacci查找,还包括数结构的二叉排序树以 ...
- Stooge排序与Bogo排序算法
本文地址:http://www.cnblogs.com/archimedes/p/stooge-bogo-sort-algorithm.html,转载请注明源地址. Stooge排序算法 Stooge ...
- JavaScript 数据结构与算法之美 - 桶排序、计数排序、基数排序
1. 前言 算法为王. 想学好前端,先练好内功,只有内功深厚者,前端之路才会走得更远. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScript ,旨在入门数据结构与算 ...
- java排序算法(八):希尔排序(shell排序)
java排序算法(八):希尔排序(shell排序) 希尔排序(缩小增量法)属于插入类排序,由shell提出,希尔排序对直接插入排序进行了简单的改进,它通过加大插入排序中元素之间的间隔,并在这些有间隔的 ...
- 排序算法的C语言实现(下 线性时间排序:计数排序与基数排序)
计数排序 计数排序是一种高效的线性排序. 它通过计算一个集合中元素出现的次数来确定集合如何排序.不同于插入排序.快速排序等基于元素比较的排序,计数排序是不需要进行元素比较的,而且它的运行效率要比效率为 ...
- Java排序 - 不实用的几个排序算法 -- 睡眠排序、猴子排序、面条排序、珠排序
介绍几个不实用的排序算法,一来可以在学习时增加一些乐趣,放松一下自己,二来可以学习一下.思考一下这些算法失败在哪里,又是否存在一些好的地方? 睡眠排序 这是一个思想比较简单,脑洞巨大的算法 -- 我们 ...
- 内部排序->选择排序->树形选择排序
文字描述 树形选择排序又称锦标赛排序; 比如,在8个运动员中决出前3名至多需要11场比赛, 而不是7+6+5=18场比赛(它的前提是甲胜乙,乙胜丙,则甲必能胜丙) 首先对n个记录的关键字进行两两比较, ...
随机推荐
- Thinkphp的S缓存用法!
/节点列表 public function node(){ if(!$node = S('node_list')){ $field = array('id', 'name', 'title', 'pi ...
- 【iCore1S 双核心板_ARM】例程八:ADC实验——电源监控
实验原理: STM32内部集成三个12位ADC,iCore1S的所有电源经过 电阻分压或者直接接入STM32的ADC的输出通道内,输入电流 经过高端电流检测芯片ZXCT1009F输入到ADC的输入通道 ...
- Foxpro数据库连接错误解决方法--【VFP DBF文件不是一个有效的路径。 确定路径名称拼写是否正确,以及是否连接到文件存放的服务器】
直接访问vfp dbf文件时报错: 错误描述: 'd:\vfpData\test.dbf'不是一个有效的路径. 确定路径名称拼写是否正确,以及是否连接到文件存放的服务器. 解决办法:Data Sour ...
- windows下更换pip源
(1)在windows文件管理器中,输入 %APPDATA% (2)会定位到一个新的目录下,在该目录下新建pip文件夹,然后到pip文件夹里面去新建个pip.ini文件 (3)在新建的pip.ini文 ...
- Springboot学习笔记(二)-定时任务
springboot中要使用定时任务需要在配置类或启动类上标注注解@EnableScheduling,并在定时执行的无参方法上标注注解@Scheduled,程序启动后会根据@Scheduled所提供的 ...
- python通过input()函数输入的内容是什么类型
说明: 通过input()函数,可以从标准输入读取内容,那么读到的内容是什么类型呢. 通过type()函数可以进行判断,另外,通过input()函数的官方解释,从标准输入读取一个字符串.所以,应该是字 ...
- 原生App切图的那些事儿
如何切图? 了解iphone界面的尺寸 最小的分辨率是320x480,我们把这个尺寸定为基准界面尺寸(baseline),基准尺寸所用的图标定为1倍图(1x). 在实际设计过程中,为了降低设计成本,一 ...
- ThinkingInJava 学习 之 0000004 初始化与清理
1. 用构造器确保初始化. 不接受任何参数的构造器叫做默认构造器. Tree tree = new Tree(12); 如果Tree(int)时Tree类的唯一的构造器,那么编译器将不会允许你以其他任 ...
- lua第三方库
一.Lua 包管理工具 1.LuaRocks luarocks 是Lua常用的包管理工具(还有一个是LuaDist),其安装方式请参考官网:https://luarocks.org/#quick-st ...
- iOS开发之--解决 swap file “*.swp”already exists!问题
刚才我在vim导入第三方库的时候,突然发现我把podfile的名字打错了,然后我直接终止了进程,然后你懂得出错了,,E325......., 其实使用vim编辑文件实际上是先copy一份临时文件,病映 ...