排序

1.选择排序

  选择排序的基本原理是:每次找出最小的元素放到前面,具体的:

  对于一组给定的记录a1,a2,a3.......an;

  第一次循环:从a2开始到an,依次和a1进行比较,找到小于a1当中最小的一个,与a1进行交换,否则不交换;

  第二次循环:从a3开始到an,依次和a2进行比较,找到小于a2当中最小的一个,与a2进行交换,否则不交换;

  ......

  一直到循环结束。

  egg{2 4 6 7 1 3 8 9}

    第一次1 2 [6 7 4 3 8 9]

    第二次1 2 3 [7 4 6 8 9]

    第三次1 2 3 4 [7 6 8 9]

    第四次1 2 3 4 6 [7 8 9]

    第五次1 2 3 4 6 7 [8 9]

    第六次1 2 3 4 6 7 8 [9]

    第七次1 2 3 4 6 7 8 9 

  代码如下:

#include <iostream>
using namespace std;

void Swap(int &a,int &b)
{
    int temp=a;
    a=b;
    b=temp;
}

//选择排序算法 时间复杂度为o(n*n)
void SelectSort(int a[], int length)
{
    int i=0;//外层循环 从0到length-2
    int j=0;//内层循环 从i+1到length-1
    int MinPos=0;//每次比较的最小元素位置
    for (i=0;i<length-1;i++)//从第一个到倒数第二个元素
    {
        MinPos=i;
        for (j=i+1;j<length;j++)
        {
            if (a[j]<a[MinPos])
            {
                MinPos=j;
            }
        }
        if(MinPos!=i)//找到了比a[i]更小的元素 交换
        {
            Swap(a[i],a[MinPos]);
        }
    }
}

2.插入排序

  插入排序算法原理:假设前k个元素是有序排列的,新插入元素依次和前k个元素比较,插入到合适的位置,具体地:

  给出一组记录,a1,a2,a3…….an;
  第一次循环:假定a1有序,插入a2,如果a2小于该元素,则交换a1,a2,否则不交换,此时a1 a2有序;
  第二次循环:插入a3,如果a3小于a2,交换a3,a2,再将a2与a1比较,如果小则换,此时a1 a2 a3有序;
  ......
  第n-1次循环:插入a[n],依次和前面所有元素比较,交换。

  egg:{4,2,6,7,1,3,8,9}


    第一次[2 4]6 7 1 3 8 9
    第二次[2 4 6]7 1 3 8 9
    第三次[2 4 6 7]1 3 8 9
    第四次[1 2 4 6 7]3 8 9
    第五次[1 2 3 4 6 7]8 9
    第六次[1 2 3 4 6 7 8]9
    第七次[1 2 3 4 6 7 8 9]

void InsertSort(int a[],int length)
{
    int i=0;
    int j=0;
    for (i=0;i<length-1;i++)
    {
        for (j=i+1;j>=1;j--)
        {
            if (a[j]<a[j-1])
            {
                Swap(a[j],a[j-1]);
            }
        }
    }
}

 3.冒泡排序:

   冒泡排序算法原理:从第一个记录开始依次对相邻的两个元素进行比较,如果前面的元素大于后面的元素就交换,这样,第一轮下来,最大的数已经排到了末尾,然后再对前n-1个元素进行如上交换。
  egg:{4 2 6 7 1 3 9 8}
    第一次:[2 4 6 1 3 7 8]9
    第二次:[2 4 1 3 6 7]8 9
    第三次:[2 1 3 4 6]7 8 9
    第四次:[1 2 3 4]6 7 8 9
    第五次:[1 2 3]4 6 7 8 9
    第五次:[1 2]3 4 6 7 8 9
    第六次:[1]2 3 4 6 7 8 9
    第七次: 1 2 3 4 6 7 8 9

void BubbleSort( int a[] , int length )
{
    int i,j;
    for (i = 0; i < length-1; i++)  
    {
        for (j = 1; j < length - i; j++)  
        {
            if (a[j -1]> a[j])  
            {
                Swap(a[j],a[j-1]);
            }
        }
    }
}

4.希尔排序

  算法原理:将无序记录分为若干个子列,子列是间隔抽取的,间隔个数为增量,对各个子列进行插入排序;然后选一个更小的增量,重新划分子列,再次进行插入排序......;最后选择增量为1,也就是整个序列作为一个序列,进行插入排序,是最终记录成为有序。

  增量选择,首选Incre=length/2,每次缩小一倍,直到Incre为1;
  

  egg:{4,2,6,7,1,3,8,9}

    Incre=8/2=4
    第一个子列4,1 排序后 1,4
    第二个子列2,3 排序后 2,3
    第三个子列6,8 排序后 6,8
    第四个子列7,9 排序后 7,9
  第一次排序完后
    1 2 6 7 4 3 8 9
    

    增量选为4/2=2

    第一个子列1 6 4 8 排序后 1 4 6 8
    第二个子列2 7 3 9 排序后 2 3 7 9
  第二次排序完后
    1 2 4 3 6 7 8 9
    

    增量选为1
  第三次排序完后
    1 2 3 4 6 7 8 9

 代码如下:

void ShellSort(int a[], int length)
{
    int i=0;
    int j=0;
    int temp=0;
    for (int Incre = length / 2; Incre > 0; Incre /= 2)
        for (i = Incre; i < length; ++i)
        {
            temp = a[i];
            for(j = i -Incre; j >= 0 ; j -=Incre)
            {
                if (temp<a[j])
                {
                    a[j+Incre] = a[j];
                }
                else
                    break;
            }  
            a[j+Incre] = temp;
        }
}

5.快速排序:

快速排序是一个就地排序,分而治之,大规模递归的算法。从本质上来说,它是归并排序的就地版本。快速排序可以由下面四步组成。

(1) 如果不多于1个数据,直接返回。
(2) 一般选择序列最左边的值作为支点数据。
(3) 将序列分成2部分,一部分都大于支点数据,另外一部分都小于支点数据。
(4) 对两边利用递归排序数列。

快速排序比大部分排序算法都要快。尽管我们可以在某些特殊的情况下写出比快速排序快的算法,但是就通常情况而言,没有比它更快的了。快速排序是递归的,对于内存非常有限的机器来说,它不是一个好的选择。 

 初始化关键字: [49 38 65 97 76 13 27 49]

第一趟排序之后[27 38 13 ]49 [76 97 65 49]

第二趟排序之后[13] 27 [38] 49 [49 65] 76 [97]

第三趟排序之后13 27 38 49 49 [65] 76 97

最后结果:     13 27 38 49 49 65 76 97

void QuickSort(int array[],int low ,int high)//调用的时候 high的位置要填length-1
{
    int i;
    int j;
    int idex;
    if (low>=high)
    {
        return;
    }
    i=low;
    j=high;
    idex=array[i];
    while (i<j)//执行完后 一趟排序 第一个元素将所有元素分成左右两等分
    {
        while (i<j&&array[j]>=idex)//从右向左寻找第一个小于idex的数
        {
            j--;
        }
        if (i<j)//如果找到了 交换两个数 并且i右移一下
        {
            array[i]=array[j];
            i++;
        }
        while (i<j&&array[i]<idex)//从左向右寻找第一个大于idex的数
        {
            i++;
        }
        if (i<j)
        {
            array[j]=array[i];
            j--;
        }
    }
    array[i]=idex;//中间划分位置元素
    QuickSort(array,low,i-1);//左半部分递归
    QuickSort(array,i+1,high);//右半部分递归
}

6.归并排序:

       归并排序先分解要排序的序列,从1分成2,2分成4,依次分解,当分解到只有1个一组的时候,就可以排序这些分组,然后依次合并回原来的序列中,这样就可以排序所有数据。合并排序比堆排序稍微快一点,但是需要比堆排序多一倍的内存空间,因为它需要一个额外的数组。

初始关键字: [49]  [38]  [65]  [97]  [76]  [13]  [27]

一趟归并后:[38 49] [65 97] [13 76] [27]

两趟归并后:[38 49   65 97]  [13  27  76]

三趟归并后:[13 27   38 49    65  76  97

void copyArray(int source[], int dest[],int len,int first)
{
    int i;
    int j=first;
    for(i=0;i<len;i++)
    {
        dest[j] = source[i];
        j++;
    }
}


void merge(int a[],int left,int right)
{
    int begin1 = left;
    int mid = (left+right)/2 ;
    int begin2 = mid+1;
    int k=0;
    int newArrayLen = right-left+1;
    int *b = (int*)malloc(newArrayLen*sizeof(int));
    while(begin1<=mid && begin2<=right)
    {
        if(a[begin1]<=a[begin2])
            b[k++] = a[begin1++];
        else
            b[k++] = a[begin2++];
    }
    while(begin1<=mid)
        b[k++] = a[begin1++];
    while(begin2<=right)
        b[k++] = a[begin2++];
    copyArray(b,a,newArrayLen,left);
    free(b);
}




void mergeSort(int a[],int left,int right)
{
    int mid;// 保证至少有两个元素
    if(left < right)
    {
        mid = (left+right)/2;
        mergeSort(a,left,mid );
        mergeSort(a,mid +1,right);
        merge(a,left,right);
    }
}

7.堆排序http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html

堆排序适合于数据量非常大的场合(百万数据)。

堆排序不需要大量的递归或者多维的暂存数组。这对于数据量非常巨大的序列是合适的。比如超过数百万条记录,因为快速排序,归并排序都使用递归来设计算法,在数据量非常大的时候,可能会发生堆栈溢出错误。

堆排序会将所有的数据建成一个堆,最大的数据在堆顶,然后将堆顶数据和序列的最后一个数据交换。接下来再次重建堆,交换数据,依次下去,就可以排序所有的数据。


void AdjustMaxHeap(int a[],int pos ,int len)
{
    int temp;
    int child;
    for (temp=a[pos];2*pos+1<=len;pos=child)
    {
        child=2*pos+1;//根节点的左孩子
        if (child<len&&a[child]<a[child+1])//如果左孩子小于右孩子 将右孩子的值作为交换
        {
            child++;
        }
        if (a[child]>temp)//如果值大的孩子大于根节点,把该孩子节点值赋给父节点
        {
            a[pos]=a[child];
        }
        else //如果两个孩子都不大于根节点的值 不交换
            break;
    }
    a[pos]=temp;//将父节点的值赋给子节点
}

void HeapSort(int a[],int len)
{
    int i;
    for (i=len/2-1;i>=0;i--)//建立堆
    {
        AdjustMaxHeap(a,i,len-1);
    }
    for (i=len-1;i>=0;i--)//堆排序
    {
        Swap(a[0],a[i]);
        AdjustMaxHeap(a,0,i-1);
    }
}


 

排序方法

最好时间

平均时间

最坏时间

辅助存储

稳定性

备注

选择排序

O(n2)

O(n2)

O(n2)

O(1)

不稳定

n小好

插入排序

O(n)

O(n2)

O(n2)

O(1)

稳定

大部分有序好

冒泡排序

O(n)

O(n2)

O(n2)

O(1)

稳定

n小好

希尔排序

O(n)

O(nlogn)

O(ns)1<s<2

O(1)

不稳定

S是所选分组

快速排序

O(nlogn)

O(nlogn)

O(n2)

O(logn) 

不稳定

n大好

堆排序

O(nlogn)

O(nlogn)

O(nlogn)

O(1)

不稳定

n大好

归并排序

O(nlogn)

O(nlogn)

O(nlogn)

O(n) 

稳定

n大好

原文地址:https://www.cnblogs.com/mu-tou-man/p/3906488.html