常用的排序算法

一、冒泡排序(交换排序)点击打开链接

1.基本思想冒泡排序将被排序的记录数组R[1..n]垂直排列,每个记录R[i]看作是重量为ki的气泡。根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R;凡扫描到违反本原则的轻气泡,就使其向上"漂浮"。如此反复进行,直到最后任何两个气泡都是轻者在上,重者在下为止。

冒泡排序的具体过程如下

       第一步,先比较k1和k2,若k1>k2,则交换k1和k2所在的记录,否则不交换。继续对k2和k3重复上述过程,直到处理完kn-1和kn。这时最大的排序码记录转到了最后位置,称第1次起泡,共执行n-1次比较。
      与第一步类似,从k1和k2开始比较,到kn-2和kn-1为止,共执行n-2次比较。

      依次类推,共做n-1次起泡,完成整个排序过程。


2.时间复杂度

若文件的初始状态是正序的,一趟扫描即可完成排序。所需关键字比较次数为n-1次,记录移动次数为0。因此,冒泡排序最好的时间复杂度为O(n)。

       若初始文件是反序的,需要进行n-1趟排序。每趟排序要进行n-i次关键字的比较(1<=i<=n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较次数达到最大值n(n-1)/2=O(n^2),移动次数也达到最大值3n(n-1)/2=O(n^2)。因此,冒泡排序的最坏时间复杂度为O(n^2)。


3.稳定性

虽然冒泡排序不一定要进行n-1趟,但由于它的记录移动次数较多,故平均性能比直接插入排序要差得多。冒泡排序是就地排序,且它是稳定的。


4.代码

void    bubble_sort(int a[], int n)
{
    int     i = 0;
    int     j = 0;
    int     swap; 
    int     flag = 0; 

    for ( i=0; i<n-1; i++) 
    {
        flag = 0;
        for ( j=0; j<n-i-1; j++) 
        {
            if ( a[j+1]<a[j] ) 
            {
                swap = a[j+1];
                a[j+1] = a[j];
                a[j] = swap;
                flag = 1;
            }
        }

        if ( 0 == flag ) 
        {
            break;
        }
    }
}


二、直接选择排序(选择排序)

1、思想:首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,然后放到排序序列末尾。以此类推,直到所有元素均排序完毕。具体做法是:选择最小的元素与未排序部分的首部交换,使得序列的前面为有序。


2、时间复杂度

   最好情况下:交换0次,但是每次都要找到最小的元素,因此大约必须遍历N*N次,因此为O(N*N)。减少了交换次数! 
   最坏情况下,平均情况下:O(N*N)


3、稳定性

由于每次都是选取未排序序列A中的最小元素x与A中的第一个元素交换,因此跨距离了,很可能破坏了元素间的相对位置,因此选择排序是不稳定的!


4、代码

void    dir_sort(int    a[], int    n)
{
    int     i = 0;
    int     j = 0;
    int     k = 0;
    int     temp = 0;

    for ( i=0; i<n-1; i++) 
    {
        k = i;
        for ( j=i+1; j<n; j++) 
        {
            if ( a[j] < a[k] ) 
            {
                k = j;
            }
        }

        if ( k != i ) 
        {
            temp = a[k];
            a[k] = a[i];
            a[i] = temp;
        }
    }
}


三、快速排序(交换排序)

1、思想:它是由冒泡排序改进而来的。在待排序的n个记录中任取一个记录(通常取第一个记录),把该记录放入适当位置后,数据序列被此记录划分成两部分。所有关键字比该记录关键字小的记录放置在前一部分,所有比它大的记录放置在后一部分,并把该记录排在这两部分的中间(称为该记录归位),这个过程称作一趟快速排序。


2、算法复杂度    

   最好的情况下:因为每次都将序列分为两个部分(一般二分都复杂度都和logN相关),故为 O(N*logN)  
   最坏的情况下:基本有序时,退化为冒泡排序,几乎要比较N*N次,故为O(N*N)


3、稳定性  
   由于每次都需要和中轴元素交换,因此原来的顺序就可能被打乱。如序列为 5 3 3 4 3 8 9 10 11会将3的顺序打乱。所以说,快速排序是不稳定的!


4、代码

#include <stdio.h>
#include <stdlib.h>

void print(int  a[], int    n)
{
    int     j = 0;

    for ( j=0; j<n; j++) 
    {
        printf ("%d ", a[j]);
    }
    printf ("\n");
}

void    swap(int *a, int *b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

int    partition(int    a[], int low, int high)
{
    int     privotkey = a[low];

    while ( low < high ) 
    {
        while ( low<high && a[high]>=privotkey ) 
        {
            --high;
        }
        swap(&a[low], &a[high]);

        while ( low<high && a[low]<=privotkey ) 
        {
            ++low;
        }
        swap(&a[low], &a[high]);
    }
    //print(a, 10);

    return low;
}

void quick_sort(int a[], int low, int high)
{
    int     privotkey = 0;

   if(low<high)
    {
        privotkey = partition(a, low, high);
        quick_sort(a, low, privotkey-1);
        quick_sort(a, privotkey+1, high);
    }
}

int main (int argc, char **argv)
{
    int     a[10] = {3, 1, 5, 7, 2, 4, 9, 6, 10, 8};

    print(a, 10);
    quick_sort(a, 0, 9);
    print(a, 10);

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值