内部排序->其它->地址排序(地址重排算法)
文字描述
当每个记录所占空间较多,即每个记录存放的除关键字外的附加信息太大时,移动记录的时间耗费太大。此时,就可以像表插入排序、链式基数排序,以修改指针代替移动记录。但是有的排序方法,如快速排序和堆排序,无法实现表排序。这种情况下就可以进行“地址排序”,即另设一个地址向量指示相应记录的位置;同时在排序过程中不移动记录而移动记录地址向量中相应分量的内容。见示意图,(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个记录的关键字进行两两比较, ...
随机推荐
- 【Android】Android布局文件的一些属性值
第一类:属性值 true或者 false android:layout_centerHrizontal 水平居中 android:layout_centerVertical 垂直居中 androi ...
- 在Centos 6 64bit 上安装 Hyperic HQ 5.8.2.1 中文版
原文:https://my.oschina.net/hyperichq/blog/306791 环境描述: [test@tester ~]$ cat /etc/issue CentOS release ...
- java框架篇---hibernate之连接池
Hibernate支持第三方的连接池,官方推荐的连接池是C3P0,Proxool,以及DBCP.在配置连接池时需要注意的有三点: 一.Apche的DBCP在Hibernate2中受支持,但在Hiber ...
- 【iCore4 双核心板_ARM】例程二十二:LWIP_UDP实验——以太网数据传输
实验现象: 核心代码: int main(void) { system_clock.initialize(); led.initialize(); adc.initialize(); delay.in ...
- 【emWin】例程二十九:窗口对象——Messagebox
简介: 使用MESSAGEBOX 小工具可在带有标题栏和“确定”按钮(必须按下才能关闭窗口)的 框架窗口中显示消息.本实验通过点击下图中的按键来创建一个Messagebox对话框. 触摸校准(上电可选 ...
- WebService学习总结——调用第三方提供的webService服务
互联网上面有很多的免费webService服务,我们可以调用这些免费的WebService服务,将一些其他网站的内容信息集成到我们的Web应用中显示,下面就以获取天气预报数据. 气象中心的管理系统将收 ...
- 【转】iframe页面跳转时,导致父页面滚动!该怎么解决?
HTML code <body> <form id="form1" runat="server"> <iframe id=&quo ...
- Java面向对象的基本概念(对象、封装、继承、多态、抽象、接口、泛型)
对象:是一个自包含的实体,用一组可识别的特征和行为来标识. 类:具有相同的属性和功能的对象的抽象合集.(类关键字class,首字母大写). 实例:就是一个真实的对象. 实例化:创建对象的过程,关键字是 ...
- 弹出框插件——dialog
基于jquery和dot.js弹出框插件,兼容IE6+等其他浏览器. 思想:弹出框元素插入body节点中,并在页面垂直居中显示(fixed定位),触发确定和关闭事件绑定. 注意ie6包含两个问题:一. ...
- [Linux] ssh-key 公钥文件格式
SSH 协议(Secure Shell 协议)最初在 1995 年由芬兰的 Tatu Ylönen 设计开发,由 IETF(Internet Engineering Task Force)的网络工作小 ...