一个好的排序算法,应该兼具时间复杂度和空间复杂度的优势,目前为止可以做到的排序算法中,时间复杂度最低的也是 n*log n,因此,要想优化排序算法,你必须先知道该从哪几个可能的算法进行优化,这篇博客,我会将几种最常见也最容易出现在面试题中的排序算法罗列下来,并且做一个完整的比较
1.直接插入算法 直接插入算法的算法思想
(1)默认数组已经有序
(2)这时候如果你要继续放进去元素,就要从数组中的最后一个元素进行比较 (3)如果插入值x小于最后的值那就继续朝前走,直到遇到比它更小的值,,然后把之前的元素全部后移一位,再把x插进去
(4)如果x比最后一个值还大,那就直接放在最后一位的后面 代码如下
void InsertSort(int *a,size_t n)
{
int tag=3;
int tmp;
for(size_t i=0;i<n-1;i++)
{
DataType end=i;
tmp=a[end+1];
while(end> 0 && a[end]>tmp)//如果大于tmp
{
a[end+1]=a[end];//向后移动
end--;
}
a[end+1]=tmp;//将tmp插入
}
}
2.希尔排序(直接插入排序的优化算法)
思想:希尔排序的代码和插入排序没有太大的差异,它们之间有一个小小的区别就是,希尔排序加入了多趟预排序,正是这多趟预排序,让它的时间复杂度降低了不少,当然,这里的时间复杂度还和你选取的tag有关,接下来,我就把希尔排序的实现步骤写下来
(1)所谓预排序,就是在进行整体插入的基础上,将一个数组相邻tag距离的元素先进行一次粗排
(2)在粗排一次之后,将tag缩小1,这样,每个相邻tag-1距离的元素都会进行一次插入排序,经过又一轮的预排序之后,整个数组中的元素已经相邻接近有序了,这个时候,当tag等于1的时候,就会进行最后一次插入排序,数组就完全有序了
希尔排序相比较直接插入排序的优化就在于,当数组是最坏的情况时,插入排序算法要将每个元素都挪动n-1次,这样算下来,时间复杂度已经达到了n^2
而使用希尔排序,经过多次预排序,数组已经接近有序了,所以插入时需要挪动的数据量也是很小的,这样就可以大大减小时间复杂度
代码如下
void ShellSort(int *a,size_t n)
{
int tag=3; //加入的标志符
int tmp;
while(tag>1)
{
tag=tag/3+1; //tag每次减1
for(size_t i=0;i<n-tag;i++)
{
DataType end=i;
tmp=a[end+tag];
while(end>=0 &&a[end]>tmp)
{
a[end+tag]=a[end]; //向后移动元素
end-=tag;
}
a[end+tag]=tmp;
}
}
3.选择排序
选择排序具有稳定性,这是一般排序所不具备的,但是选择排序还是有一些缺点,时间复杂度比较高,算法较难优化。选择排序的思想
(1)每次选出一个最大最小值,记住他们的下标
(2)然后再让第一个元素和最后一个元素分别和他们进行交换操作,然后将数组需要比较的数据减少2
(3)控制下标, 依次循环,当走到中间位置时,数组也就排好序了
代码如下
void SelectSort(int *a,int b)
{
int i=0;
int left=0;
int right=9;
int min=0;
int max=0;
while(left<right)
{
min=max=left;
for(i=left;i<=right;++i)
{
if(a[i]<a[min])
{
min=i; //标记最小元素的下标
}
if(a[i]>a[max])
{
max=i;//标记最大元素的下标
}
}
swap(&a[left],&a[min]);//交换min和max位置的元素
if(left!=max)
swap(&a[right],&a[max]);
++left;
--right; //数组缩减
}
4.快速排序(左右指针法 递归版本)
快速排序的左右指针法,其实就是定义了两个下标来控制数组的排序,大概思路如下
(1)先假设一个数组中有10个元素,然后将最后一个元素的值保存在key中。
(2)设置一个 begin和一个end,将begin初始化为0,end初始化为9
(3)从最左边开始找第一个比key大的值,如果找到就保存当前下标
(4)从最右边开始从后往前找第一个比key小的值,如果找到就保存当前下标
(5)如果两个值都找到了就交换这两个位置的值
(6)如果没找到,就将key和从右边开始找的第一个值进行交换
(7)这样经过一次循环交换,大的值已经在key的后面,小的在key的前面
(8)通过递归将key左右两边的元素再进行两次分组,分别让他们有序
代码如下
int QuickSort1(int a[],int left,int right)
{
int key=a[right];
int begin=left;
int end=right;
while(begin<end)
{
if(a[begin]<=key)
{
begin++;
continue;
}
if(a[end]>=key)
{
end--;
continue;
}
swap(&a[begin],&a[end]);
}
swap(&a[begin],&a[right]);
return begin;
}
void QuickSort(int a[],int left,int right)
{
assert(a);
if(left>=right)
return;
int div=QuickSort1(a,left,right);
QuickSort(a,left,div-1);
QuickSort(a,div+1,right);
}