面试必须掌握的四大经典排序算法

一个好的排序算法,应该兼具时间复杂度和空间复杂度的优势,目前为止可以做到的排序算法中,时间复杂度最低的也是 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);

}
  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值