各种排序算法总结

来源:互联网 发布:数据挖掘的案例分析 编辑:程序博客网 时间:2024/05/21 20:50

排序的稳定性和复杂度

不稳定:

选择排序(selection sort)— O(n2)

快速排序(quicksort)— O(nlog2n)平均时间, O(n2)最坏情况;对于大的、乱序串列一般认为是最快的已知排序

堆排序 (heapsort)— O(nlog2n)

希尔排序 (shell sort)— O(n(1+s)) s为0~1的数

基数排序(radix sort)— O(n·k)需要O(n)额外存储空间 (K为特征个数)

稳定:

插入排序(insertion sort)— O(n2)

冒泡排序(bubble sort)— O(n2)

归并排序 (merge sort)— O(nlog2n);需要O(n)额外存储空间

二叉树排序(Binary tree sort)— O(nlogn);需要O(n)额外存储空间

计数排序 (counting sort) — O(n+k);需要O(n+k)额外存储空间,k为序列中Max-Min+1

桶排序 (bucket sort)— O(n);需要O(k)额外存储空间

插入排序

插入排序的基本思想是:将第i个记录的关键字Ki与前面记录r[1]~r[i-1]的关键字从后向前进行顺次比较,将所有关键字大于Ki的记录依次向后移动一个位置,直到遇到一个关键字小于或等于Ki的记录,该记录的位置即为r[i]的插入位置。

如:

将33,12,25,46,33,68,19,80排序
插入排序

void InsertSort(int r[], int n)//n为需要比较数个数{    int i,j;    for(int i=2;i<=n;i++)    {        if(r[i]<r[i-1])//如果r[i]>r[i-1],则为正确序列,不用排序            {                r[0]=r[i];//监视哨备份,即将r[i]作为关键字                for(j=i-1;r[0]<r[j];j--)                {                    r[j+1]=r[j];    //记录后移                }                r[j+1]=r[0];//插入到正确位置            }    }}

希尔排序

希尔排序的基本思想是:将需要排序的序列划分成为若干个较小的子序列,对子序列进行插入排序,通过则插入排序能够使得原来序列成为基本有序。这样通过对较小的序列进行插入排序,然后对基本有序的数列进行插入排序,能够提高插入排序算法的效率。

希尔排序的划分子序列不是像归并排序那种的二分,而是采用的叫做增量的技术,例如有八个元素的数组进行希尔排序,首先选择增量为8/2=4。

r[1]和r[5]比较,r[2]和r[6]比较……

如:

将46,25,68,33,33,19,12,80排序
这里写图片描述

void ShellSort(int r[], int n)//n为需要比较数个数{    int i,j;    int dk;//dk为增量    for(dk=n/2;d>=1;dk=dk/2)    {    for(i=dk+1;i<=n;i++)    {        if(r[i]<r[i-dk])//如果r[i]>r[i-dk],则为正确序列,不用排序        {            r[0]=r[i];//监视哨备份,即将r[i]作为关键字            for(j=i-dk;j>0&&r[0]<r[j];j-=dk)            {                r[j+dk]=r[j];   //记录交换            }            r[j+dk]=r[0];//插入到正确位置        }    }  }}

冒泡排序

冒泡排序的基本思想是:顺次比较相邻两个记录的关键字大小,如果逆序就交换位置。

void BubbleSort(int r[], int n)//n为需要比较数个数{    int i,j,temp;    int flag=1;//flag为标志位    for(i=1;i<=n-1&&flag;i++)    {        flag=0;//如果顺序正确则不进行比较,直接输出。        for(j=1;j<=n-i;j++)        {            if(r[j]>r[j+1])                {                        temp=r[j];                        r[j]=r[j+1];                        r[j+1]=temp;                        flag=1;                }           }       }}

快速排序

快速排序的基本思想是:从待序列中任意选择一个记录,以该记录为关键字,凡小于该关键字的记录均移动到该记录之前,大于该关键字的记录移动到该关键字之后。致使一趟排序之后,记录的无序序列被分割成左右两个子序列,然后再分别对两个子序列进行递归快排,直到每个子序列只含有一个记录为止。

如:

将46,68,12,25,33,80,19,33排序
这里写图片描述
这里写图片描述

void QKpass(int r[],int low,int high)//low,high分别是标志位{    r[0]=r[low];    while(low<high)//当标志位重叠时结束    {        while(low<high&&r[high]>r[0])//如果high>关键字,前移        {            --high;         }           r[low]=r[high];//如果high<关键字,将high赋给low        while(low<high&&r[low]<r[0])//如果low<关键字,后移        {            ++low;          }        r[high]=r[low]; //如果low>关键字,将low赋给high      }       r[low]=r[0];//当标志位重叠时,将r[0]关键字赋值给r[low]    return low;//返回标志位}void QKSort(int r[],int low,int high){    int pos;    if(low<high)    {            pos=QKpass(r,low,high);            QKSort(r,low,pos-1);//对比关键字小的部分序列的快排            QKSort(r,pos+1,high);//对比关键字大的部分序列的快排    }   }

简单选择排序

简单选择排序的基本思想是:从第一个记录开始遍历,每一趟找出一个最小值。即,第一趟,r[1]与r[2]~r[n]每一个进行比较,如果r[i]<r[1],则r[1]和r[i]值进行交换。第二趟,r[2]与r[3]~r[n]每一个进行比较,如果r[i]<r[2],则r[2]和r[i]值进行交换…….

如:

将33,68,46,33,25,80,19,12排序
这里写图片描述

void SelectSort(int r[],int n){    int k,temp;    for(int i=0;i<=n-1;i++)    {            k=i;            for(j=i+1;j<=n-1;j++)            {                if(r[j]<r[k])                    {                        k=j;                        }               }            if(k!=i)                {                    temp=r[i];                    r[i]=r[k];                    r[k]=temp;                }    }   }

堆排序
堆排序的基本思想是:先建一个“大顶堆”,即先选一个关键字最大的记录,然后与序列中最后一个记录交换,之后继续对序列中前n-1记录进行“筛选”,重新将它调整为一个“大顶堆”,再将堆顶记录和第n-1个记录交换,如此反复,直至排序结束。

如:
对46,12,33,72,68,19,80,33进行堆排序

堆的筛选,过程如下:
这里写图片描述

void HeapAdjust(int r[],int s,int n){    int temp=r[s];    for(int j=2*s;j<=n;j*=2)    {        if(j<n&&r[j]>r[j+1])//沿值较小的节点向下筛选            j++;        if(temp<r[j])            break;            r[s]=r[j];            s=j;    }       r[s]=temp;//插入}

建初始堆过程如下:
这里写图片描述

void CreatHeap(int r[],int n){    for(i=n/2;i>=1;i--)         HeapAdjust(r,i,n);}

堆排序过程如下:
这里写图片描述
这里写图片描述

void HeapSort(int r[],n){    CreateHeap(r,n);        for(i=n;i>=2;i--)    {        r[0]=r[1];        r[1]=r[i];        r[i]=r[0];        HeapAdjust(r,1,i-1);        }}

基数排序
基数排序的基本思想是:对于数字型或字符型的单关键字,可以看做是由多个位数或多个字符构成的多关键字。
如:
对921,435,628,285,862,225,448,193,430排序。
首先按照“个位数”取值,分别为0,1…….,9“分配”成10组,之后按照0到9收集在一起。
然后按照“十位数”分配收集。
然后“百位数”。
然后……
这里写图片描述

//提取关键字第m位的数字值int digit(KeyType k,int m,int r){    int i,d;    if(m==0)        return k%r;    d=r;    for(i=1;i<m;i++)        d*=r;    return ((int)(key/d)%r);    }
//基数排列void RadixSort(Type r[],int n,int m,int r)//L中的关键字为m位r进制数,L的长度为n{    LinkQueue *Queue;    int i,j,k;    q=(LinkQueue *)malloc(r*sizeof(LinkQueue));    for(i=0;i<r;i++)        InitQueue(&Queue[i]);    for(i=0;i<m;i++)    {        for(j=0;j<n;j++)        {            k=digit(L[j].key,i,r);            EnterQueue(&Queue[k],L[j]);         }           k=0;        for(j=0;j<r;j++)            for(;!IsEmptyQueue(Queue[j]);k++)                DeleteQueue(&Queue[j],&(L[k]));    }   }