排序算法(对各种排序算法本质、性能的总结)

来源:互联网 发布:照片变成视频软件 编辑:程序博客网 时间:2024/06/05 15:19

冒泡排序

基本思想

重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。

实现

冒泡排序算法的运作如下:
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对(从前往后操作)。在这一点,最后的元素应该会是最大的数
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

void bubble_sort(int a[], int n){    int i, j, temp;    for (j = 0; j < n - 1; j++)        for (i = 0; i < n - 1 - j; i++)        {            if(a[i] > a[i + 1])            {                temp = a[i];                a[i] = a[i + 1];                a[i + 1] = temp;            }        }}

性能

时间复杂度

最好的时间复杂度:正序时O(n)

稳定的排序

额外空间

O(1)

快速排序

冒泡排序的优化。

基本思想:

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

实现:

一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。

void quickSort(int s[], int l, int r)  {      if (l< r)      {                int i = l, j = r, key = s[l];          while (i < j)//循环直到i==j        {              while(i < j && s[j]>= key) //从右向左找第一个小于key的数(结束循环时j满足s[j]<key)                j--;               if(i < j)                  s[i++] = s[j];//写s[i]=s[j]也可以;本质是一个交换,但是由于s[i]的值用key存储,所以不用赋值            while(i < j && s[i]< key) //从左向右找第一个大于等于key的数                  i++;               if(i < j)                  s[j--] = s[i];          }          s[i] = key;          quickSort(s, l, i - 1); // 递归调用,分治         quickSort(s, i + 1, r);      }  }  

性能

额外的空间:

快排可以说需要的空间为O(1),因为是原地排序,不需要额外空间;也可以说需要的空间是O(n),因为在递归调用时有栈的开销,当然最坏情况是O(n),平均情况是O(logn)。

不稳定的排序

希尔排序

希尔排序本质是插入排序

堆排序

本质是选择排序,选择排序中在unsorted部分选择最大(小)的值复杂度O(n),堆排序利用二叉树的结构复杂度为O(logn)

归并排序

基本思想

建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。
归并操作:将两个或两个以上有序的数列(或有序表),合并成一个仍然有序的数列(或有序表)。

实现

第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列
第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置
第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
重复步骤3直到某一指针超出序列尾
将另一序列剩下的所有元素直接复制到合并序列尾

性能

求逆序对对数

具体思路是,在归并的过程中计算每个小区间的逆序对数,进而计算出大区间的逆序对数
归并排序的交换次数就是这个数组的逆序对个数
归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来。
在合并的过程中(设l<=i<=mid,mid+1<=j<=h),当a[i]<=a[j]时,并不产生逆序数;当a[i]>a[j]时,在前半部分中比a[i]大的数都比a[j]大,将a[j]放在a[i]前面的话,逆序数要加上mid+1-i。因此,可以在归并排序中的合并过程中计算逆序数.

0 0
原创粉丝点击