文字描述

  和之前的插入排序比,表插入排序可以保证排序过程中不移动记录;因此表插入排序所用的存储结构和之前的顺序存储不同,表插入排序采用静态链表类型作为待排记录序列的存储结构,设数组中下标0的分量为表头结点,并令表头结点记录的关键字取最大整数MAXINT。表插入排序的基本操作仍然是将一个记录插入到已经排好序的有序表中,和直接插入排序有相似之处,不同之处在于是以修改2次指针值代替1次移动记录。

示意图

算法分析

  时间复杂度仍然是n*n, 因为排序过程中需要和数据个数相同的指针值,所以辅助空间为n,是稳定的排序方法。

代码实现

见附录1


  另外, 与表插入排序相关的还有一个重排算法,  先依旧从文字描述, 示意图, 复杂度和代码实现四方面分析该算法.

文字描述

表插入排序的结果只是求得一个有序链表,则只能对它进行顺序查找, 不能进行随机查找. 为了能实现有序表的折半查找,尚需对记录进行重新排列.

重排记录的做法是: 顺序扫描有序链表, 将链表中第i个结点移动至数组的第i个分量重. 若第i个最小关键字的结点是数组中下标为p且p>i的分量,则互换SL.r[i]和SL.r[p],且令SL.r[i]中指针域的值改为p; 由于此时数组中所有小于i的分量中已经是“到位”的分量,则当p<i时,应顺链继续查找直到p>i或p==i为止。

示意图

算法分析

在重排记录的过程中,最坏情况是每个记录到位都必须进行一次记录的交换,即3次移动记录,所以重排记录至多需进行3(n-1)次记录的移动, 它并不增加表插入排序的时间复杂度,还是n*n, 辅助空间为1

代码实现

见附录1


附录1

 #include <stdio.h>
#include <stdlib.h> #define DEBUG //静态链表容量
#define SIZE 100
//最大整数
#define MAX 100 #define EQ(a, b) ((a) == (b))
#define LT(a, b) ((a) < (b))
#define LQ(a, b) ((a) <= (b)) //定义关键字类型为整数类型
typedef int KeyType;
//定义其它数据项为整数类型
typedef int InfoType; //记录类型
typedef struct{
//关键字项
KeyType key;
//其他数据项
InfoType otherinfo;
}RedType; //表结点类型
typedef struct{
//记录项
RedType rc;
//指针项
int next;
}SLNode; //静态链表类型
typedef struct{
//0号单元为表头结点
SLNode r[SIZE];
//链表当前长度
int length;
}SLinkListType; //顺序打印静态链表中的关键字和指向下个数据的指针
void PrintSList(SLinkListType SL){
int i = ;
printf("下标值:");
for(i=; i<=SL.length; i++){
printf("[%d] ", i);
}
printf("\n关键字:");
for(i=; i<=SL.length; i++){
printf(" %-4d", SL.r[i].rc.key);
}
printf("\n其他值:");
for(i=; i<=SL.length; i++){
printf(" %-4c", SL.r[i].rc.otherinfo);
}
printf("\n\n");
return ;
} //表插入排序算法
void TableInsertSort(SLinkListType *SL)
{
//0号位表头结点,存最大整数值MAX
SL->r[].rc.key = MAX;
//首先将静态链表中数组下标为1的分量和表头结点构成一个循环链表
SL->r[].next = ;
SL->r[].next = ; //和直接插入排序相似,只是不移动记录,只是改变指针指
int i = , q = , p = ;
for(i=; i<=SL->length; i++){
q = ;
p = SL->r[q].next;
while(LQ(SL->r[p].rc.key, SL->r[i].rc.key)){
q = p;
p = SL->r[q].next;
}
//以修改2次指针值代替移动记录
SL->r[q].next = i;
SL->r[i].next = p;
}
return ;
} /*
* 表插入排序相关的重排算法
*
* 根据静态链表SL中各结点的指针调整记录位置,
* 使得SL中各记录按关键字升序排序
*
*/
void Arrange(SLinkListType *SL)
{
//p指示第一个记录的当前位置
int p = SL->r[].next, q = ;
int i = ;
SLNode tmp; //SL.r[1..i-1]中记录已按关键字有序排列
for(i=; i<SL->length; ++i){
//第i个记录的在SL中的当前位置应不小于i
while(p<i){
p = SL->r[p].next;
}
//q指示尚未调整的表尾
q = SL->r[p].next;
if(p != i){
//交换记录,使第i个记录到位
tmp = SL->r[p];
SL->r[p] = SL->r[i];
SL->r[i] = tmp;
//指向被移走的记录,使得以后可由while循环找回
SL->r[i].next = p;
}
//p指示尚未调整的表尾,为找第i+1个记录作准备
p = q;
#ifdef DEBUG
printf("第%d趟重排:\n", i);
PrintSList(*SL);
#endif
}
} int main(int argc, char *argv[])
{
if(argc < ){
return -;
}
SLinkListType SL;
int i = ;
for(i=; i<argc; i++){
if(i>SIZE)
break;
SL.r[i].rc.key = atoi(argv[i]);
SL.r[i].next = ;
SL.r[i].rc.otherinfo = 'a'+i-;
}
SL.length = (i-);
SL.r[].rc.key = ;
SL.r[].rc.otherinfo = '';
/*进行表插入排序*/
TableInsertSort(&SL);
printf("表插入排序之后的静态链表:\n");
PrintSList(SL); /*重排记录,使它能满足有序表的折半查找*/
Arrange(&SL);
return ;
}

表插入排序和重排算法

运行

内部排序->插入排序->其它插入排序->表插入排序的更多相关文章

  1. 内部排序算法(交换排序,插入排序)注意点(C语言实现)

    对于算法思想的理解可以参考下面的这个帖子,十大经典排序算法(动图演示) - 一像素 - 博客园,因为算法的逻辑和数学很像,相应的基础资料一般也能在网上找到,所以,本帖子这谈论一些重要的注意点,其他人讲 ...

  2. Java实现各种内部排序算法

    数据结构中常见的内部排序算法: 插入排序:直接插入排序.折半插入排序.希尔排序 交换排序:冒泡排序.快速排序 选择排序:简单选择排序.堆排序 归并排序.基数排序.计数排序 直接插入排序: 思想:每次将 ...

  3. 常见内部排序算法对比分析及C++ 实现代码

    内部排序是指在排序期间数据元素全部存放在内存的排序.外部排序是指在排序期间全部元素的个数过多,不能同时存放在内存,必须根据排序过程的要求,不断在内存和外存之间移动的排序.本次主要介绍常见的内部排序算法 ...

  4. 七内部排序算法汇总(插入排序、Shell排序、冒泡排序、请选择类别、、高速分拣合并排序、堆排序)

    写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的随意序列,又一次排列成一个按keyword有序的序列.因此排序掌握各种排序算法很重要. 对以下介绍的各个排序,我们假定全部排 ...

  5. 【排序】表插入排序算法(C语言版)

    排序耗时的操作主要分为两种:查找比较.记录移位. 1.表插入排序 在查找比较基础上,尽量减少记录移位步数,可以令排序操作耗时降低,表插入排序正是为减少移位次数而出现的. 在数据结构上,数据是存储在静态 ...

  6. 数据结构C语言版 表插入排序 静态表

    数据结构C语言版 表插入排序.txt两个人吵架,先说对不起的人,并不是认输了,并不是原谅了.他只是比对方更珍惜这份感情./*  数据结构C语言版 表插入排序  算法10.3 P267-P270  编译 ...

  7. 数据结构 - 表插入排序 具体解释 及 代码(C++)

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/u012515223/article/details/24323125 表插入排序 具体解释 及 代码 ...

  8. lintcode-173-链表插入排序

    173-链表插入排序 用插入排序对链表排序 样例 Given 1->3->2->0->null, return 0->1->2->3->null 标签 ...

  9. 排序算法三:Shell插入排序

    排序算法三:Shell插入排序 声明:引用请注明出处http://blog.csdn.net/lg1259156776/ 引言 在我的博文<"主宰世界"的10种算法短评> ...

随机推荐

  1. 对于Python中@property的理解和使用

    @property 这个我们在很多代码中都会用到,简单讲即为一个只读属性的调用 如果需要有修改权限,需要再加一个@属性名.setter 例: #!/usr/bin/env python # -*- c ...

  2. 嵌入式开发之hi3519---fifo ringbuffer

    http://blog.csdn.net/CSSEIKOCS/article/details/50790085 http://blog.csdn.net/xuanwolanxue/article/de ...

  3. swoole web服务

    web.php <?php $http = ); $http->on('request', function ($request, $response) { var_dump($reque ...

  4. [IR] Concept Search and LSI

    基于术语关系的贝叶斯网络信息检索模型扩展研究 LSI 阅读笔记 背景知识 提出一种改进的共现频率法,利用该方法挖掘了索引术语之间的相关关系,将这种相关关系引入信念网络模型,提出了一个具有两层术语节点的 ...

  5. js的 new Date()日期格式化显示以及js获取时间戳

    一.日期格式化显示: 对 new Date() 得到日期的进行格式显示扩展,扩展方法如下: // 对Date的扩展,将 Date 转化为指定格式的String // 月(M).日(d).小时(h).分 ...

  6. 【Docker】退出容器和进入容器

    运行容器:docker run -it 镜像名 /bin/bash 退出容器: exit 或者 Ctrl+P+Q 查看容器:docker ps -a 查看运行的容器:docker ps 重启容器:do ...

  7. [Java] Apache Ant 构建基础教程

    环境:Ubuntu 12.04, java 1.7.0, ant 1.8.2. 前言 Apache Ant 是一个软件自动化构建工具,构建过程包括编译.测试和部署等.它和 Make 工具相似,但由 J ...

  8. C# 根据类名创建类的实例对象

    因为我使用这个方法的类都是和AbstractScenePageDTO处于一个命名空间以及程序集下的,所以获取命名空间和程序集的时候,直接使用AbstractScenePageDTO这个类进行获取,这样 ...

  9. 深入理解 Java 虚拟机之学习笔记(1)

    本书结构: 从宏观的角度介绍了整个Java技术体系.Java和JVM的发展历程.模块化,以及JDK的编译 讲解了JVM的自动内存管理,包括虚拟机内存区域的划分原理以及各种内存溢出异常产生的原因 分析了 ...

  10. [原]Jenkins(十四)---jenkins示例:admin管理所有项目,新建用户只能看部分项目

    /** * lihaibo * 文章内容都是根据自己工作情况实践得出. *如有错误,请指正 * 版权声明:本博客欢迎转发,但请保留原作者信息! http://www.cnblogs.com/horiz ...