现在的位置: 首页 > 综合 > 正文

七种常见的排序方式

2013年03月28日 ⁄ 综合 ⁄ 共 3988字 ⁄ 字号 评论关闭

   几种基本的排序方式,很容易混淆,每次过一段时间后又忘了,所以这次一次性将这些排序

方式集中整理了一下。首先是下面的分析表:

排序方式 英文缩写 算法思想 时间复杂度 稳定性
冒泡排序 bubble_sort 相邻比较,大数往后排 N^2 稳定
交换排序 exchange_sort 前面的某个数逐个与后面的比较,小数往前移 N^2 不稳定
插入排序 insert_sort 无序的数往有序中插入 N^2 稳定
希尔排序 shell_sort 步长不为一的插入排序 介于NlgN和N^2之间 不稳定
快速排序 quick_sort 先分成大小两部分,再递归 NlgN 不稳定
归并排序 merge_sort 先分解成一个个数据,再递归合并 NlgN 稳定
堆排序 heap_sort 先建立大根堆,然后再将依次第一个数放到“最后”,下滤 NlgN 不稳定

然后我将列出他们的代码:

1.冒泡排序:
#include <stdio.h>
void swap(int *a, int *b)
{
    int tmp;
    tmp  = *a;
    *a = *b;
    *b = tmp;
}

void bubble(int *array, int len)
{
    int i,j;
    for(i = 0; i < len; i++)
    {
        for(j = 0; j < len - i - 1;j++)
        {
            if(array[j] > array[j + 1])
                swap(&array[j], &array[j + 1]);
        }
    }
}
      这应该是最简单的排序方式,每次排序后,最大的那个值会放到最后,然后
将排序的长度缩短一个。
2.交换排序:
void select(int *array, int len)
{
    int i,j;
    for(i = 0; i < len; i++)
    {
        for(j = i; j < len; j++)
        {
            if(array[j] < array[i])
                swap(&array[j], &array[i]);
        }
    }
}
       交换排序和冒泡排序正好相反,每次将一个最小的数,排到前面,我任何交换排序
和选择排序基本没有区别,因为他们都是将小数往前拍,只不过,选择排序设置了一个
对比,而不是每次去互换
3.插入排序:
void insert(int *array, int len)
{
    int i,j,key;
    for(i = 1; i < len; i++)
    {
        key = array[i];
        j = i;
        while(j > 0 && array[j - 1] > key)
        {
            array[j] = array[j - 1];
            j--;
        }
        array[j] = key;
    }
}
     插入排序的思想就是,前面的数据已经排好了,然后没有排好的数据,逐个插入进去,找到合适的位置。
4.希尔排序:
void shell(int *array, int len)
{
    int i,j,tmp,increment;
    for(increment = len / 2; increment > 0; increment /= 2)
    {
        for(i = increment; i < len; i++)
        {
            tmp = array[i];
            for(j = i; j >= increment;j -= increment)
            {
                if(tmp < array[j - increment])
                    array[j] = array[j - increment];
                else
                    break;
            }
            array[j] = tmp;
        }
    }
}
       希尔排序可以说和插入排序思想基本一致,只是他不是去逐个比较,而是设定了步长。
效率要比前面三种都高很多,另外他的时间复杂度也和步长有关,计算起来很麻烦
5.快速排序:
void quick_sort(int *array, int left, int right)
{
    if(left >= right - 1)
    {
        if((right == (left + 1)) && array[left] > array[right])
            swap(&array[left], &array[right]);
        return;
    }
    int i,j,cmp;
    cmp = array[right];
    i = left;
    j = right - 1;
    while(i < j)
    {
        while(array[i] < cmp && i < right)
            i++;
        while(array[j] > cmp && j > left)
            j--;
        if(i < j)
            swap(&array[i], &array[j]);
    }
    swap(&array[i], &array[right]);
    quick_sort(array, left, i - 1);
    quick_sort(array, i + 1, right);
}
       快速排序利用的是分治的思想,快速排序有很多可以改进的地方,例如参考元的选择,当需要排序的数据个数
很少时,可以采用其他方式等等。在这段代码中,需要注意的是:cmp = array[right],而不是left,另外
if((right == (left + 1)) && array[left] > array[right])这个条件判断也很重要
6.归并排序:
void merge(int *array, int left, int mid, int right)
{
    int tmp[right - left + 1];
    int i = 0, save_left = left;
    int center = mid;
    while(left < mid && center <= right )
    {
        if(array[left] <= array[center])
            tmp[i++] = array[left++];
        else
            tmp[i++] = array[center++];
    }
    while(left < mid)
        tmp[i++] = array[left++];
    while(center <= right)
        tmp[i++] = array[center++];
    i = 0;
    while(save_left <= right)
        array[save_left++] = tmp[i++];
}

void merge_sort(int *array, int left, int right)
{
    if(left >= right - 1)
    {
        if(left == right - 1 && array[left] > array[right])
            swap(&array[left], &array[right]);
        return;
    }
    int mid = (left + right) / 2;
    merge_sort(array, left, mid - 1);
    merge_sort(array, mid, right);
    merge(array, left, mid, right);
}

        归并排序我觉得和快速排序的思想正好相反,一个是先分后合,一个是先合后分。

需要注意的是代码中的   

       merge_sort(array, left, mid - 1);    

       merge_sort(array, mid, right);    

        merge(array, left, mid, right);这三句是容易出问题的,

如果没有    if(left == right - 1 && array[left] > array[right])       

                     swap(&array[left], &array[right]);这个判断,

那么就必须分解为:    merge_sort(array, left, mid);    

                                merge_sort(array, mid + 1, right);    

                                merge(array, left, mid + 1, right);

这是因为:  mid = (left + right) / 2          

                  left <=  mid < right 

分解成:    

            merge_sort(array, left, mid - 1);     

            merge_sort(array, mid, right);

例如当left = 2,right = 3时,会导致死循环。

7.堆排序:

void down(int *arr, int i, int size)
{
    int child;
    int tmp;
    for(tmp = arr[i]; leftchild(i) < size; i = child)
    {
        child = leftchild(i);
        if(child != size - 1 && arr[child + 1] > arr[child])
            child++;
        if(tmp < arr[child])
            arr[i] = arr[child];
        else
            break;
    }
    arr[i] = tmp;
}

void heap_sort(int *array, int len)
{
    int i;
    //建堆
    for(i = len / 2; i >= 0; i--)
    {
        down(array, i, len);
    }
    i = len - 1;
    //让最大值从堆中去掉,然后下滤
    while(i > 0)
    {
        swap(&array[0], &array[i]);
        down(array, 0, i);
        i--;
    }
}

    需要注意的是,如果是升序排列,建的是大根堆,另外上面的程序可以避免额外的空间消耗,

因为他每次将最大值放到最后只有,堆的大小,减掉了一个。











































【上篇】
【下篇】

抱歉!评论已关闭.