插入排序:把一个数插入到一个有序的序列中,并要求插入后此数据序列仍然有序。这种排序思想就是插入排序。

那么对于一个原始无序的序列,哪里找有序的部分呢?这个很简单,可以把序列分为两个部分,第一个元素是第一部分,其余元素是第二部分。第一个部分只有一个元素,当然是有序的!对于如何把其余元素插入到第一部分中去,按插入策略,可分为如下几种插入方法:

直接插入:把余下元素一个一个插入有序表中,每次都从有序表的最后一个元素开始比较,若是小于该元素:data<a[i],则再与前一个元素比较data[i-1],...直到找到合适位置,最后把该位置及其以后的元素都向后移动:a[j]=a[j-1],腾出一个位置让新元素插入。这也是最简单的插入排序算法。

看代码:

void InsertSort(int *a, int n)  //直接插入排序
{if(a==NULL || n<=1)  //assert(a && n>0);return;for(int i=1; i<n; i++){int j=i; int temp=a[i];while(j && temp<a[j-1]){a[j]=a[j-1];j--;}a[j]=temp;}
}


交换插入:也可以在比较的过程中,直接交换前后位置的元素,一步一步地把插入的元素交换到合适的位置,如下:

void InsertSort(int *a, int n)  //直接插入排序
{if(a==NULL || n<=1)  //assert(a && n>0);return;for(int i=1; i<n; i++){int j=i; while(j && a[j]<a[j-1]){swap(a[j],a[j-1]);   //交换元素 j--;}}
}

折半插入:在直接插入中,我们每次都是把一个元素插入到一个有序的序列中。为了使找到位置更高效,我们可以借鉴二分查找的方法,减少比较次数,快速找到合适的插入位置。这就是折半插入的来历。

根据二分查找时,区间选取的不同,可细分为如下两种:注意比较两者的细微差别哦

代码一:左闭右闭 [low,high]

void BInsertSort(int *a, int n)  //Binary Insert Sort  折半插入排序
{assert(a && n>0);for(int i=1; i<n; ++i){int low,high;low=0;high=i-1;int mid;while(low<=high)  //使用二分查找,寻找插入的位置 {mid=low+((high-low)>>1);    //这种写法,有效避免溢出if(a[i]>a[mid])low=mid+1;elsehigh=mid-1;}int temp=a[i];for(int j=i; j>low; j--)  //移动元素 a[j]=a[j-1];a[low]=temp;  //在合适位置,插入。这里为什么是 low? 得仔细想想!  }
}

代码二:左闭右开 [low,high)

void BInsertSort(int *a, int n)  //Binary Insert Sort  折半插入排序
{assert(a && n>0);for(int i=1; i<n; ++i){int low,high;low=0;high=i;    //这里的写法,要注意 int mid;while(low<high)  //使用二分查找,寻找插入的位置 {mid=low+((high-low)>>1);if(a[i]>a[mid])low=mid+1;elsehigh=mid;}int temp=a[i];for(int j=i; j>low; j--)  //移动元素 a[j]=a[j-1];a[low]=temp;  //在合适位置,插入 }
}

update:2014-5-31 16:33

写完这篇博客后,发现很多人对二分插入,最后应当插入的位置不是很明白,为什么代码一中最后新元素的插入位置是a[low]=temp呢?下面教你透彻了解二分插入的前前后后。

测试代码:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void printArray(int a[], int n)   //打印数组
{for(int i=0; i<n; i++)printf("%-4d",a[i]);printf("\n");
}
void BInsertSort(int a[], int n)   //折半插入
{for(int i=1; i<n; i++){int low,high;low=0,high=i-1;int mid;printf("i=%d\n",i);printArray(a,n);while(low<=high){mid=low+((high-low)>>1);printf("low=%d,high=%d,mid=%d\n",low,high,mid);if(a[i]<a[mid])high=mid-1;else low=mid+1;printf("low=%d,high=%d,mid=%d\n",low,high,mid);}int temp=a[i];for(int j=i; j>low; j--)a[j]=a[j-1];a[low]=temp;   //这里如写high+1,则上面的j>low,应改为j>high+1,原因见下面的分析}
}
int main()
{const int N=6;srand((unsigned)time(NULL));int a[N];for(int i=0; i<N; i++)   //打印下标 printf("%-4d",i);printf("\n");for(int i=0; i<N; i++)a[i]=rand()%100;BInsertSort(a,N);printArray(a,N);system("pause");return 0;
}

其中的一次运行结果是:

0    1    2    3    4    5       //下标

i=1                                  //插入下标为i的数,下同

83  19  83  1    8    38

low=0,high=0,mid=0

low=0,high=-1,mid=0

i=2

19  83  83  1    8    38    //上一次插入后的结果,19插入了0号位置,上一轮low=0

low=0,high=1,mid=0

low=1,high=1,mid=0

low=1,high=1,mid=1

low=2,high=1,mid=1

i=3

19  83  83  1    8    38    //83插入2号位值,其实未移动,上一轮low=2

low=0,high=2,mid=1

low=0,high=0,mid=1

low=0,high=0,mid=0

low=0,high=-1,mid=0

i=4

1  19  83  83    8    38    //1插入了0号位置,上一轮low=0

low=0,high=3,mid=1

low=0,high=0,mid=1

low=0,high=0,mid=0

low=1,high=0,mid=0

i=5

1   8   19  83   83    38    //8插入了1号位置,上一轮low=1

low=0,high=4,mid=2

low=3,high=4,mid=2

low=3,high=4,mid=3

low=3,high=2,mid=3

1   8   19   38   83   83   //38插入了3号位置,上一轮low=3,至此排序结束

从代码中我们可以知道,low,high,mid的值是两个一组的,上一组是a[i]和a[mid]未经比较以前的,下一组是比较后,经过调整的。调整结果要么是low=mid+1,要么是high=mid-1。

不知大家从上面的数据看出了什么。对!我们现在可以清楚的肯定:新元素的插入位置就是low。并且还发现high比low要小一,即high+1才与low相等。这是显然的,否则while循环如何结束。

我想此刻大家的疑惑肯定是解开了。那么插入位置的写法就很随意了:low和high+1都行!

用同样的方法对代码二这种左闭右开的区间经行测试,会发现:插入位置仍然是low,最后while循环终止的条件是low和high相等。

以上代码,大家最好动手测试一下。有问题,及时通知我修改哦!

转载请注明出处,本文地址:http://blog.csdn.net/zhangxiangdavaid/article/details/27373183

若是对你有所帮助,或是觉得有意思,希望顶一个哦。

专栏目录:

  • 数据结构与算法目录
  • c指针

插入排序:直接插入、交换插入、折半插入相关推荐

  1. 算法研究:插入类排序(简单插入,折半插入,希尔排序)

    百度百科:有一个已经有序的数据序列,要求在这个已经排好的数据序列中插入一个数,但要求插入后此数据序列仍然有序,这个时候就要用到一种新的排序方法--插入排序法,插入排序的基本操作就是将一个数据插入到已经 ...

  2. (1.3.3)插入排序:直接插入、交换插入、折半插入

    插入排序:把一个数插入到一个有序的序列中,并要求插入后此数据序列仍然有序.这种排序思想就是插入排序. 那么对于一个原始无序的序列,哪里找有序的部分呢?这个很简单,可以把序列分为两个部分,第一个元素是第 ...

  3. 插入排序:表折半插入

    在前一篇插入排序:表插入中.我们用静态链表的存储方式.直接插入的策略,构建了一种新的插入排序算法:表插入. 有人可能会想到:相同是静态链表的形式,为什么不使用更高效的折半插入策略呢?这样的想法真的非常 ...

  4. 插入类排序--直接插入、折半插入、希尔

    一. 直接插入排序 1. 执行过程: 原始序列:49,38,65,97,76,13,27 1)一开始只看49 49        38,65,97,76,13,27 2)插入38.38<49,所 ...

  5. 直接插入_折半插入(python)

    折半插入默认待插入值左侧部分已经排好顺序,找到合适位置,对插入点右侧已排好序的部分后移一步操作,循环直到全部点排序完成 1 ''' 2 折半插入 3 时间复杂度O(pow(n,2) 4 ''' 5 d ...

  6. C语言基本数据结构之五(折半插入,堆排序,冒泡排序,快速排序,并归排序)

    上一篇大概写了序列的查找算法,这次就聊聊序列的几种重要的排序(大神自动飘过~~~) 一.算法分析 1.1 直接插入排序 基本思想:将文件中的记录分为有序区.无序区,不断地从无序区中顺序提取记录,按关键 ...

  7. 【数据结构----笔记4】插入排序算法之【折半插入排序算法】

    /*__________________________________________________________________________________________________ ...

  8. oracle数据库开多线程,学习笔记:Oracle表数据导入 DBA常用单线程插入 多线程插入 sql loader三种表数据导入案例...

    天萃荷净 oracle之数据导入,汇总开发DBA在向表中导入大量数据的案例,如:单线程向数据库中插入数据,多线程向数据表中插入数据,使用sql loader数据表中导入数据案例 1.Oracle数据库 ...

  9. mongodb 批量插入_MongoDB批量插入– MongoDB插入很多

    mongodb 批量插入 We will look into MongoDB bulk insert today. Multiple documents can be inserted at a ti ...

最新文章

  1. TP5 实现转盘抽奖
  2. linux每日命令(14):less命令
  3. mysql引擎测试_MySQL MyISAM引擎和InnoDB引擎的性能测试
  4. I/O多路转接之select
  5. 【lucene系列学习二】Lucene实现高亮显示关键词
  6. 拟牛顿法-DFP算法举例与matlab代码实现(转载+整理)
  7. 代码单元测试:gtest
  8. 服务器开机忘记密码怎么修改,服务器忘记mysql密码怎么修改?
  9. SSAS的MDX语句整理
  10. DataGridView使用技巧一:获取或设置当前单元格的内容
  11. webapp检测手机运动方向,可实现手机摇一摇功能的触发
  12. GDAL 2.0版本RPC校正速度测试
  13. C++的C4305和C4800的编译警告
  14. 电脑五笔,电脑键盘五笔指法练习表
  15. TIA PORTAL西门子PLC的CPU固件版本兼容问题
  16. 读后感:《约翰·伯格与先锋集团》
  17. 阿里云服务器 免费获取SSL证书 配置HTTPS安全访问
  18. 搜索命令:whereis/which/locate/find/grep
  19. win10 小娜搜索空白
  20. JS验证通过之后才提交表单

热门文章

  1. javaScript和html的区别与联系
  2. 基于PHP聊天室的编程思想
  3. 常见的HTTP网络状态码汇总+HttpServletResponse源码
  4. 温度指示报警电路设计报告
  5. 在线PS把图片背景变成透明(灰白格子)
  6. ARM9嵌入式Linux开发-内存与IO操作
  7. 详解康托展开与逆康托展开
  8. Switch中的参数
  9. Android Binder驱动的工作机制之要旨
  10. 文献阅读系列-2|TBC-Net: A real-time detector for infrared small