排序算法小结

来源:互联网 发布:淘宝订单接口 编辑:程序博客网 时间:2024/06/02 05:27

1、冒泡排序

相邻的数据进行交换。如果有n个数,则需要比较n-1次,每次比较后,较大的数都会排到后面(下面),故以后相邻的数据之间可以少比较一次。当数据之间没有再进行交换了,则停止排序。故可以用do…while…来实现。

时间复杂度:O(N^2)。稳定。
冒泡排序代码:
void sort(int* a, int n)
{
    bool changeFlag;
    do{
        changeFlag = false;
        for(int i = 1; i < n; i++){
            if(a[i] < a[i-1]){
                swap(a[i], a[i-1]);
                changeFlag = true;
            }
        }
    }while(changeFlag);
}

2、插入排序

从左到右一组数,除第一个数外(故n个数,只需比较n-1次),依次取出与其左面的数进行比较,若小于相邻的左边的数,则将相邻的左边的数向右一个位置,直到其不小于其相邻的左边的数,此时,找到了要插入的位置。注意,在进行比较之前,需要将待排序的数复制一份,防止在移位的时候,将待排序的数覆盖。

时间复杂度:O(N^2)。稳定。

插入排序代码:

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

3、选择排序

典型的例子是将扑克牌无序的摆放,每次从中选一个最小的,依次将其排序。则第i次只需对剩余的n-i个数进行排序。现将当前的第i个数设为最小,然后依次的与当前值进行比较,遇到更小的值则更新此最小值,直到找到剩余n-i个数的最小值,然后将最小值与第i个位置上的数进行交换。因为最后一个数肯定是最大的,不需要在进行比较,因此进行了n-1趟比较。

时间复杂度:O(N^2)。不稳定。

选择排序代码:

void sort(int* a, int n)
{
    for(int i=0; i < n-1; i++)
    {
        int min = i;
        for(int j = i+1; j < n; j++)
        {
            if(a[j] < a[min])
                min = j;
        }
        swap(a[min],a[i]);
    }
}

4、快速排序

算法思路:

  • 找分界值(一般取首元素或者中间元素)
  • 分组即划分子表,小于分界值的元素靠左边,大于分界值的元素靠右边
  • 将小于分界值即左边的元素中最右边的元素与分界值进行交换
  • 对分界值左右两组子表再进行排序
  • 两步递归
  • 结束:左右元素个数均不超过一个,直接完成

时间复杂度:O(NlogN)。不稳定。
快速排序代码:
void sort(int* a, int n)
{
    if(n <= 1)  return;
    if(n == 2){
        if(a[1] < a[0]) swap(a[1], a[0]);
        return;
    }
    swap(a[n/2], a[0]);
    int bounds = a[0];
    int* L = a+1;
    int* R = a+n-1;


    while(L<R){
        while(L<R && *L<bounds)
            ++L;
        while(a<R && !(*R<bounds))
            --R;
        if(L < R)   swap(*L, *R);
    }
    if(*R < bounds) swap(*R, a[0]);
    sort(a, R-a);
    sort(R+1, n-1-(R-a));
}

5、归并排序

归并排序的关键是将两个排好序的文件组合成一个较大的有序文件。

快速排序是一个不断划分排序的过程,类似于化整为零。而归并排序则是先化整为零在化零为整,是分治算法的典型应用。其子过程包括划分子表和合并子表。

归并操作思路:

  • 申请一段辅助空间,其大小与需要进行排序的文件大小相同,即空间复杂度为O(n);
  • 将带排序的文件一分为二,将其视作两个子表,将这两个子表按照元素的大小依次放入辅助空间中;
  • 归并操作完成;

划分子表操作:

  • 将待排序文件一分为二,通过两个递归对待排序数据元素进行二分;
  • 两个递归后面紧跟着一个归并操作;
  • 递归终止的条件为待排序文件的首尾关键字(索引)相等。

时间复杂度:O(NlogN)。稳定。

归并排序代码:
#include <iostream>
using namespace std;


void Merge(int sourceArr[], int tempArr[], int startIndex, int midIndex, int endIndex)
{
    int i = startIndex, j = midIndex+1, k = startIndex;
    while(i != midIndex+1 && j != endIndex+1)
    {
        if(sourceArr[i] < sourceArr[j])
            tempArr[k++] = sourceArr[i++];
        else
            tempArr[k++] = sourceArr[j++];
    }
    while(i != midIndex+1)
        tempArr[k++] = sourceArr[i++];
    while(j != endIndex+1)
        tempArr[k++] = sourceArr[j++];
    for(i=startIndex; i<=endIndex; i++)
        sourceArr[i] = tempArr[i];
}


void MergeSort(int sourceArr[], int tempArr[], int startIndex, int endIndex)
{
    int midIndex;
    if(startIndex < endIndex)
    {
        midIndex = (startIndex+endIndex)/2;
        MergeSort(sourceArr, tempArr, startIndex, midIndex);
        MergeSort(sourceArr, tempArr, midIndex+1, endIndex);
        Merge(sourceArr, tempArr, startIndex, midIndex, endIndex);
    }
}


int main()
{
    int a[8] = {50,10,20,30,70,40,80,60};
    int b[8];
    MergeSort(a,b,0,7);
    for(int i = 0; i < 8; i++)
        cout << a[i] << ' ';
    cout << endl;
    return 0;
}
0 0
原创粉丝点击