直接插入排序
直接插入排序的思想:
- 选取待排序数组的第一个元素,作为一个有序区间,将后面待排序的数组看作是一个无序区间
- 选取有序区间的最后一个元素key与待排序区间的第一个元素进行比较,如果待排序区间的第一个元素的值小于key的值,就将有序区间的最后一个元素后移,再将key与已经有序的区间其他值进行比较,直到找到一个元素的值小于key的值,将key插入到该元素后面的位置
直接插入排序用图表示如下:
代码如下:
#include<iostream>
#include<assert.h>
using namespace std;
//直接插入排序 9,1,5,8,3,7,4,6,2
void InsertSort(int *arr, int sz)
{
assert(arr);
for (int i = 0; i < sz; i++)
{
int end = i;//记录有序区间的最后一个位置
int key = arr[end + 1];//记录待排序的元素
while (end>=0)
{
if (arr[end] > key)//有序区间最后一个元素的值大于key
{
arr[end + 1] = arr[end];// 就将最后一个元素后移一位
--end;//再将key值与有序区间的其他值进行比较
}
else
break;
}
arr[++end] = key;
}
}
void Printf(int arr[], int sz)
{
assert(arr);
for (int i = 0; i < sz; i++)
{
cout << arr[i]<<" ";
}
}
int main()
{
int arr[] = { 90, 10, 50, 80, 30, 70, 40, 60, 20 };
int sz = sizeof(arr) / sizeof(arr[0]);
InsertSort(arr, sz-1);
Printf(arr, sz);
system("pause");
}
时间复杂度&&空间复杂度分析
【时间复杂度】
- 最好情况:要排序的表根本就是有序的,只是arr[i]与arr[i-1]的比较,比较n-1次,由于没有移动数据,时间复杂度为O(n)
- 最坏的情况:待排的表是逆序的,需要1+2+3+4+…+n=(n+1)(n-1)/2次,时间复杂度为O(n^2)
- 一般情况:O(n^2)
- 同样是时间复杂度为O(n^2),直接插入排序比冒泡排序和选择排序性能更佳
【空间复杂度】
由于存储的是有限数据的个数,故时间复杂度为O(1)
【适用范围】适合于少数数量的排序
希尔排序
希尔排序的思想:
- 希尔排序在数据进行排序之前,先对数据进行预排序,使之接近有序,然后再利用直接插入排序的思想进行排序
- 先将待排序的元素分割成若干个子序列(由相隔某个增量的元素组成),然后依次缩减增量进行排序,待整个序列中的元素基本有序时,再用直接插入排序的方法对整个数组进行排序
希尔排序用图解释为:
希尔排序代码如下:
#include<iostream>
#include<assert.h>
using namespace std;
//希尔排序 9,1,5,8,3,7,4,6,2
void ShellSort(int *arr, int sz)
{
int gap = sz;//记录分割增量
while (gap > 1)
{
gap = gap / 3 + 1;
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 Printf(int arr[], int sz)
{
assert(arr);
for (int i = 0; i < sz; i++)
{
cout << arr[i]<<" ";
}
}
int main()
{
int arr[] = { 90, 10, 50, 80, 30, 70, 40, 60, 20 };
int sz = sizeof(arr) / sizeof(arr[0]);
ShellSort(arr, sz-1);
Printf(arr, sz);
system("pause");
}
gap=gap/3+1确保了最后一次进行的是gap=1的直接插入排序;
且每一次循环进入gap的减小,都可以使得一次预排序的结果数据更加的接近有序;
while循环里面的for循环,成功的一次过去将不同的分组中的数据在各自的分组中都进行一次直接插入排序;
希尔排序的时间复杂度&&空间复杂度
【时间复杂度】
- 希尔排序的时间复杂度为:O(n^(3/2))
- 由于记录是跳跃式的移动,希尔排序并不是一种稳定的排序算法
直接插入排序和希尔排序的对比
(1)当数据很多,且数据整体逆序时—-使用希尔排序
(2)当数据逆序,但数据不是很多时—-采用希尔排序和直接插入差不多
(3)当数据基本有序时,且数量不能太大(量级为千级)—–使用直接插入排序