内部排序->其它->地址排序(地址重排算法)
文字描述
当每个记录所占空间较多,即每个记录存放的除关键字外的附加信息太大时,移动记录的时间耗费太大。此时,就可以像表插入排序、链式基数排序,以修改指针代替移动记录。但是有的排序方法,如快速排序和堆排序,无法实现表排序。这种情况下就可以进行“地址排序”,即另设一个地址向量指示相应记录的位置;同时在排序过程中不移动记录而移动记录地址向量中相应分量的内容。见示意图,(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个记录的关键字进行两两比较, ...
随机推荐
- tensorflow笔记9:nn_ops.bias_add 函数
完整代码引入:from tensorflow.python.ops import nn_ops tensorflow version:1.9 代码演示: import os import tensor ...
- openfire开发文档
http://www.blogjava.net/yi88han/archive/2009/02/11/254203.html
- Ubuntu18.04启用中文输入法
Ubuntu18.04发布了,但是搜狗输入法目前尚未支持. 而18.04自带的中文输入法选择sunpinyin为预设中文输入引擎,但是并没有将sunpinyin放入iso镜像中.详情参考https:/ ...
- 1. RNN神经网络模型原理
1. RNN神经网络模型原理 2. RNN神经网络模型的不同结构 3. RNN神经网络-LSTM模型结构 1. 前言 循环神经网络(recurrent neural network)源自于1982年由 ...
- PHP扩展类ZipArchive实现压缩解压Zip文件和文件打包下载
文章转载自:https://my.oschina.net/junn/blog/104464 PHP ZipArchive 是PHP自带的扩展类,可以轻松实现ZIP文件的压缩和解压,使用前首先要确保PH ...
- Brainfuck解析器(Python)
global cs global ip global ss #global sp global ds global bp global tab global out cs='++++++++++[&g ...
- Math.Round四舍六入五取偶Math.Ceiling只要有小数都加1Math.Floor总是舍去小数
1.Math.Round:四舍六入五取偶 引用内容 Math.Round(0.0) //0Math.Round(0.1) //0Math.Round(0.2) //0Math.Round(0.3) / ...
- Swing中支持自动换行的WrapLayout
http://www.cnblogs.com/TLightSky/p/3482454.html ———————————————————————————————————————————————————— ...
- CentOS Nginx网站服务器搭建实例
Nginx是一款开源的高性能HTTP服务器和返向代理服务器. 下载.编译.安装模块: [root@localhost nginx-1.4.0]#wget http://nginx.org/ ...
- java.sql.SQLException: ORA-01578: ORACLE 数据块损坏问题解决办法
错误信息: java.sql.SQLException: ORA-01578: ORACLE 数据块损坏 (文件号 17, 块号 315703) ORA-01110: 数据文件 17: 'D:\ORA ...