【直接插入排序】和【希尔排序】
2017-07-13 16:23
169 查看
一、直接插入排序
(1)算法步骤(升序)
1>将待排序数组的第一个数拿出来看做一个已经排序好的有序区间;将后面的数列看做一个无序的待排序数列;2>从有序数列的最后一个数开始和待排序数列的第一个数key比较(即有序数列的最后一个位置的下一个位置的数),如果有序数列的最后一个数大于key,则将有序数列的最后一个数填到key的位置;然后取有序数列的前一个数和key比较,大于key则填入后一个位置,继续取有序数列前面数和key比较;直到 发现比key小的数据;将key填入该数据的后面的位置;
3>重复步骤2,直到无序数列没有数据,排序完成
——动图展示
(2)图说
(3)代码实现
#include<iostream> #include<assert.h> using namespace std; void InsertSort(int* arr,int sz)//sz为最后一个数的数组下标 { assert(arr); for(int i=0;i<sz;i++)//i代表有序区间的末尾地址,最后只能到整个区间的倒数第二个位置 { int end=i;//记录有序期间的末尾 int key=arr[end+1];//待排序的元素 while (end>=0)//end从后往前走和key比较 { if (arr[end]>key) { arr[end+1]=arr[end];//end+1位置一定放的是比end位置大的数 --end; } else break; } //出循环有两种可能,一种end<0(key插入有序区间的末尾),另一种arr[end]<key(key插入有序区间的非末尾); //出循环后end为key在有序区间的正确位置的前一个位置; arr[++end]=key; } } void printArray(int* a,int n)//打印数组 { for(int i=0;i<n;++i) { cout<<a[i]<<" "; } cout<<endl; } int Test() { int a[]={9,5,3,8,1,6,7,4}; int sz=sizeof(a)/sizeof(a[0]); InsertSort(a,sz-1); printArray(a,sz); return 0; } int main() { Test(); return 0; }
(4)测试结果
(5)时间复杂度&&空间复杂度分析
【1】时间复杂度分析:假入是把目标按升序排列;那么对于排列N个数的数组;
①最坏情况:
排序的数组为降序有序;这时最终排序完成需要比较的次数为1+2+3+…+N-1=(N-1)(N-1-1)/2,所以时间复杂度为O(N^2);
②最好情况:
所排序的数组本身就是一个升序有序数组;这时需要比较的总次数为N-1次; 所以此时时间复杂度为O(N);
③一般情况: 时间复杂度O(N^2);
【2】空间复杂度:
由于算法需要存储的是有限个数据的存储空间,故此插入排序的空间复杂度为O(1)。
【3】直接插入排序的适用范围
插入排序不适合对于数据量比较大的排序应用。
插入排序适合对数据较少的数组进行排序,例如量级小于千;
二、希尔排序
(1)简介
希尔排序为直接插入排序的优化,为了防止以上直接插入排序出现最坏情况的出现影响算法效率,希尔排序对其进行了改进;在对数据进行直接排序之前,先对数据进行预排序,使之接近有序,然后再利用直接插入排序对数据进行快速排序。总的来说,希尔排序是基于插入排序的以下两点性质而提出改进方法的:
(2)基本思想
先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序。(3)图说
(4)代码实现
#include<iostream> #include<assert.h> using namespace std; ----------//核心代码 void ShellSort(int* arr,int sz)//sz为最后元素的下标 { int gap=sz;//记录分割增量 while(gap>1) { gap=gap/3+1;//gap依次缩小,让数据更加有序 for(int i=0;i<sz-gap+1;i++) { int end=i;//该组有序区间的末尾下标 int key=arr[end+gap];//该组待排序的值 while (end>=0) { if(arr[end]>key) { arr[end+gap]=arr[end]; end-=gap; } else break; } arr[end+gap]=key; } } } ---------- void printArray(int* a,int n)//打印数组 { for(int i=0;i<n;++i) { cout<<a[i]<<" "; } cout<<endl; } int Test() { int a[]={9,5,3,8,1,6,7,4}; int sz=sizeof(a)/sizeof(a[0]); ShellSort(a,sz-1); printArray(a,sz); return 0; } int main() { Test(); return 0; }
代码解读:
gap=gap/3+1确保了最后一次进行的是gap=1的直接插入排序;且每一次循环进入gap的减小,都可以使得一次预排序的结果数据更加的接近有序;
while循环里面的for循环,成功的一次过去将不同的分组中的数据在各自的分组中都进行一次直接插入排序;
测试结果:
(5)时间复杂度&&空间复杂度分析
①一般情况:O(N)<希尔排序的时间复杂度(6)本人对希尔排序的理解
希尔排序在整体上分为两大部分,第一部分为预排序,第二部分为直接插入排序;预排序是为了可以尽快的将比较小的数放在比较靠前的位置(这里,我们都是按照升序进行叙述的);gap越大,每组最后的数据会更快的来到前面,但是gap越大,每一次预排序完成以后整体上就越不接近有序;所以要依次使gap递减,使得每次预排序完成以后数据更加接近有序;
三、直接插入排序和希尔排序的对比
(1)当数据很多,且数据整体逆序时—-使用希尔排序(2)当数据逆序,但数据不是很多时—-采用希尔排序和直接插入差不多
(3)当数据基本有序时,且数量不能太大(量级为千级)—–使用直接插入排序
相关文章推荐
- 【算法拾遗(java描写叙述)】--- 插入排序(直接插入排序、希尔排序)
- 插入排序(直接插入排序,希尔排序)
- 直接插入排序、希尔排序、冒泡排序、快速排序
- 排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序
- C++实现直接插入排序,折半插入排序,希尔排序,冒泡排序,简单选择排序,快速排序,堆排序
- 数据结构排序--直接插入和希尔排序
- 直接插入排序、折半插入排序、希尔排序
- 排序算法总结(冒泡排序、直接插入排序、希尔排序)(python实现)
- 编程实现直接插入排序、希尔排序、冒泡排序、快速排序、选择排序
- 排序(选择,冒泡,直接插入,希尔排序)
- 插入排序:直接插入排序和希尔排序
- 【排序】从直接插入排序到希尔排序
- #排序算法#【2】直接插入排序、希尔排序
- 排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序
- 比较排序总结——直接插入排序,希尔排序,选择排序,堆排序,冒泡排序,快速排序,归并排序
- 插入排序(直接插入排序、希尔排序)
- 面试利器(二)-------插入排序(直接插入排序和希尔排序(Shell排序))
- 常用排序算法之插入排序 ( 直接插入排序、希尔排序 )
- 直接插入排序、希尔排序
- C语言8种排序算法及其实现 1.希尔排序 2.二分插入法 3.直接插入法 4.带哨兵的直接排序法 5.冒泡排序 6.选择排序 7.快速排序 8.堆排序