常见算法排序,冒泡排序,快排,堆排,归并排序

排序


  1. 插入类排序
1 、直接插入排序          O(n2)      O(n)              O(n2)

每次将一个待排序元素按照关键字大小插入到已经排序的序列中去。

void insert(int a[],int n)
{
     int i,j;
     int temp;
     for(i=1;i<=n;i++)    //从第二个元素开始,因为第一个元素肯定是有序的
     {
          temp=a[i];     //temp存储a[i]防丢失
          j=i-1;
          while(j>=0 && temp<a[j])    //在i之前的元素已经是有序的
          {
               a[j+1] = a[j];
               j--;     //一个个往后移
          }
          a[j+1]=temp;
     }
}


  1. 折半插入排序         O(n2)      O(n)              O(n2)

折半查找法寻找元素插入位置。与 1 最大不同在于, 1 用的是顺序查找法。

  1. 希尔排序
    缩小增量排序。实质就是分组插入排序。 把记录按步长分组,对每组记录采用直接插入排序方法进行排序。 随着步长逐渐减小,所分成的组包含的记录越来越多,当步长的值减小到 1 时,完成排序。 一个好的增量序列有以下特征:最后一个增量必须为1;尽量避免序列中的值,尤其是相邻的值,互为倍数。

  1. 交换类排序

1 、冒泡排序          O(n2)      O(n)              O(n2)

          结束条件是一趟排序中未发生元素交换。

   基本原理:依次比较两个相邻的数, 若是按从大到小排序,将大数放前,小数放后,直到比较到最后两位数。重复上述步骤,直到一趟排序中未发生元素交换为止。

// 普通冒泡
void bubble_sort(int a[],int n)//n为数组a的元素个数
{
  //一定进行N-1轮比较
  for(int i=0; i<n-1; i++)
  {
       //每一轮比较前n-1-i个,即已排序好的最后i个不用比较
       for(int j=0; j<n-1-i; j++)
       {
             if(a[j] > a[j+1])
            {
                 int temp = a[j];
                 a[j] = a[j+1];
                 a[j+1]=temp;
            }
       }
  }
}

// 优化实现
void bubble_sort_better(int a[],int n)//n为数组a的元素个数
{
  //最多进行N-1轮比较
  for(int i=0; i<n-1; i++)
  {
      bool isSorted = true;
      //每一轮比较前n-1-i个,即已排序好的最后i个不用比较
      for(int j=0; j<n-1-i; j++)
     {
        if(a[j] > a[j+1])
        {
           isSorted = false;
           int temp = a[j];
           a[j] = a[j+1];
           a[j+1]=temp;
        }
     }
     if(isSorted) break; //如果没有发生交换,说明数组已经排序好了
  }
}

2 、快速排序          O(nlog2n)       O(nlog2n)       O(n2)

       分治的思想。分治法通常有3步:Divide(分解子问题的步骤)Conquer(递归解决子问题的步骤)、Combine(子问题解求出来后合并成原问题解的步骤)。而求解递归式的三种方法有:

(1)替换法:主要用于验证递归式的复杂度。

(2)递归树:能够大致估算递归式的复杂度,估算完后可以用替换法验证。

(3)主定理:用于解一些常见的递归式。

快排中,基准的左边全是比它小的,右边都是大的。三种取基准的方法:第一个或最后一个元素,中间元素,随机元素。

待排序列越接近有序算法效率越。当每次划分时,若都能分成两个等长的子序列时,效率会达到最大。最理想的方法是,选择的基准恰好能把待排序序列分成两个等长的子序列

递归进行的,递归需要的辅助,因此辅助空间为 O(log2n)

void quiksort(int a[],int start,int end)
{
  int low = start;
  int high= end;
  int key = a[low];

  if( start < end)
  {
       while(low <high && key<=a[high])
       high--; //如果high所在的值不比key小,就往左移动
       a[low] = a[high]; //遇到比key小的high值,就把a[high]值给a[low],a[low]原本的值已经在key里面了
       while(low < high && a[low] <= key)
            low++;
       a[high]= a[low];
       a[low]=key; //此时的low的左边全是比key小的,右边全是比key大的,把key值放大当前low位置
       quiksort(a,start,low-1);//左边重复
       quiksort(a,low+1,end);//右边重复
  }
  else
       return;
}


  1. 选择类排序

  1. 简单选择排序         

从头至尾顺序扫描未排序序列,选最小的元素与第一个进行交换。

  1. 堆排序      O(nlog2n)       O(nlog2n)       O(nlog2n)

从无序序列所确定的完全二叉树的第一个非叶子节点开始,从右向左,从下往上,对每个节点进行调整(大顶堆,小顶堆),直到无序序列中只剩下一个元素。
优点: a )最坏情况下时间复杂度也是 O(nlog2n) ,这是它相对快排最大的优点。
b )空间复杂度为 O(1) ,这是在所有时间复杂度为 O(nlog2n) 中最小的。

适用于元素很多的场合,比如 100 万个元素中选前 10 个最大的。
         堆排序相对快速排序: 1 、最好最坏情况下时间复杂度都为 O(nlog2n) ,不会出现快排最坏的 O(n2)    2 、堆排序所需的辅助空间少,是 O(1) ,而快排是 O(log2n)


4.    归并 排序      O(nlog2n)       O(nlog2n)       O(nlog2n)

     采用分治法的思想。将n个元素的序列划分为两个序列,再将两个序列划分为4个序列,直到每个序列只有一个元素,最后,再有序序列两两归并成一个有序的序列。
   归并排序时间复杂度与初始序列无关。都是 O(nlog2n) 。空间复杂度为 O(n)
   内存空间不足的时候,能够并行计算的时候使用归并排序。

//归并,将有二个有序数列a[start…mid]和a[mid+1…end]合并。把结果放到temp里面
void Merge(int a[],int temp[], int start, int mid, int end)
{
  int i = start, j=mid+1, k = start;
  while(i!=mid+1 && j!=end+1)
  {
      if(a[i] >a[j])
        temp[k++] = a[j++];     //从小到大排序,a[j]放入temp[k],然后j,k都后移一位
      else
        temp[k++] = a[i++];
  }
  while(i != mid+1)
      temp[k++] = a[i++];
  while(j != end+1)
      temp[k++] = a[j++];
  for(i=start; i<=end; i++)
      a[i] = temp[i];
}

//内部使用递归
void MergeSort(int a[], int tempArr[], int start, int end)
{
  int mid;
  if(start < end)
  {
      mid = (start+ end) / 2;
      MergeSort(a, temp, start, mid);
      MergeSort(a, temp, mid+1, end);
      Merge(a, temp, start, mid, end);
  }
}

  1. 基数排序
多关键字排序。两种,最高位优先、最低位优先。 
适用场景:序列中元素个数很多,但是组成元素的关键字的取值范围比较小。比如取值范围 0~9.

总结
1 、平均时间复杂度为 O(nlog2n)   快些归队
                      快速    希尔   归并   堆排序
2 、不稳定       快些选
               快速   希尔   选择类排序(简单选择、堆排序)
3 、特殊的空间复杂度    其他都是 O(1)       快速 O(log2n)  归并 O(n)
4 、一趟保证一个元素到底最终位置           交换类      选择类
5 、比较次数与初始序列无关       简单选择         折半插入
6 、排序趟数与初始序列       交换类排序
7 、元素基本有序 ( 正序 )              直接插入         冒泡
8 、当数据规模 n 较小      直接插入排序   简单选择排序
9 、当数据规模 n 较大,采用时间复杂度为 O(nlog2n) 的排序方法(快些归队)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值