插入排序:直接插入、交换插入、折半插入
插入排序:把一个数插入到一个有序的序列中,并要求插入后此数据序列仍然有序。这种排序思想就是插入排序。
那么对于一个原始无序的序列,哪里找有序的部分呢?这个很简单,可以把序列分为两个部分,第一个元素是第一部分,其余元素是第二部分。第一个部分只有一个元素,当然是有序的!对于如何把其余元素插入到第一部分中去,按插入策略,可分为如下几种插入方法:
直接插入:把余下元素一个一个插入有序表中,每次都从有序表的最后一个元素开始比较,若是小于该元素: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.3.3)插入排序:直接插入、交换插入、折半插入
插入排序:把一个数插入到一个有序的序列中,并要求插入后此数据序列仍然有序.这种排序思想就是插入排序. 那么对于一个原始无序的序列,哪里找有序的部分呢?这个很简单,可以把序列分为两个部分,第一个元素是第 ...
- 插入排序:表折半插入
在前一篇插入排序:表插入中.我们用静态链表的存储方式.直接插入的策略,构建了一种新的插入排序算法:表插入. 有人可能会想到:相同是静态链表的形式,为什么不使用更高效的折半插入策略呢?这样的想法真的非常 ...
- 插入类排序--直接插入、折半插入、希尔
一. 直接插入排序 1. 执行过程: 原始序列:49,38,65,97,76,13,27 1)一开始只看49 49 38,65,97,76,13,27 2)插入38.38<49,所 ...
- 直接插入_折半插入(python)
折半插入默认待插入值左侧部分已经排好顺序,找到合适位置,对插入点右侧已排好序的部分后移一步操作,循环直到全部点排序完成 1 ''' 2 折半插入 3 时间复杂度O(pow(n,2) 4 ''' 5 d ...
- C语言基本数据结构之五(折半插入,堆排序,冒泡排序,快速排序,并归排序)
上一篇大概写了序列的查找算法,这次就聊聊序列的几种重要的排序(大神自动飘过~~~) 一.算法分析 1.1 直接插入排序 基本思想:将文件中的记录分为有序区.无序区,不断地从无序区中顺序提取记录,按关键 ...
- 【数据结构----笔记4】插入排序算法之【折半插入排序算法】
/*__________________________________________________________________________________________________ ...
- oracle数据库开多线程,学习笔记:Oracle表数据导入 DBA常用单线程插入 多线程插入 sql loader三种表数据导入案例...
天萃荷净 oracle之数据导入,汇总开发DBA在向表中导入大量数据的案例,如:单线程向数据库中插入数据,多线程向数据表中插入数据,使用sql loader数据表中导入数据案例 1.Oracle数据库 ...
- mongodb 批量插入_MongoDB批量插入– MongoDB插入很多
mongodb 批量插入 We will look into MongoDB bulk insert today. Multiple documents can be inserted at a ti ...
最新文章
- TP5 实现转盘抽奖
- linux每日命令(14):less命令
- mysql引擎测试_MySQL MyISAM引擎和InnoDB引擎的性能测试
- I/O多路转接之select
- 【lucene系列学习二】Lucene实现高亮显示关键词
- 拟牛顿法-DFP算法举例与matlab代码实现(转载+整理)
- 代码单元测试:gtest
- 服务器开机忘记密码怎么修改,服务器忘记mysql密码怎么修改?
- SSAS的MDX语句整理
- DataGridView使用技巧一:获取或设置当前单元格的内容
- webapp检测手机运动方向,可实现手机摇一摇功能的触发
- GDAL 2.0版本RPC校正速度测试
- C++的C4305和C4800的编译警告
- 电脑五笔,电脑键盘五笔指法练习表
- TIA PORTAL西门子PLC的CPU固件版本兼容问题
- 读后感:《约翰·伯格与先锋集团》
- 阿里云服务器 免费获取SSL证书 配置HTTPS安全访问
- 搜索命令:whereis/which/locate/find/grep
- win10 小娜搜索空白
- JS验证通过之后才提交表单