简单介绍几种排序算法

来源:互联网 发布:手绘自拍软件 编辑:程序博客网 时间:2024/05/19 18:38

选择排序

简单选择排序

比如从小到大排序的话,从未排序序列中选出最小的和序列的首元素交换,然后再在剩下的未排序序列中选出最小的和序列的第二个元素交换,以此类推,最后形成从小到大的已排序序列。C语言代码解释如下:

void SimpleSelectionSort(ElementType A[],int N){    int i,j,min,temp;    for(i=0;i<N-1,i++){        min=i;        for(j=i+1,j<N;j++){            if(A[min]>A[j]){                //确定较小元素的位置                min=j;            }        }        //交换元素的值        temp=A[i];        A[i]=A[min];        A[min]=temp;    }}

堆排序

字面意思就是用堆这种数据结构所设计的排序算法。堆是一种特殊的二叉树,每个子节点的值总是大于或小于他的父节点,相应的分为最小堆和最大堆。C语言解释代码:

void Ajust(ElementType A[],int i,int N){    int child;    Element temp;    //将当前元素的节点和其子节点比较,将最大值放到父节点上    for(temp=A[i];(2*i+1)<N;i=child){        child=2*i+1;        if((child!=N-1)&&(A[child+1]>A[child])){            child++;        }        if(temp<A[child]){            A[i]=A[child];        }        else break;    }    A[i]=temp;//将temp放到当前位置}void heapSort(ElementType A[],int N){    int i;    ElementType temp;    //建立最大推    for(i=(N-1)/2;i>=0;i++){        Ajust(A,i,N);    }    for(i=N-1;i>0;i--){        //将堆顶元素与当前堆的最后一个元素i互换        temp=A[0];A[0]=A[i];A[i]=temp;        //重新建立最大堆        Ajust(A,0,i);    }}

插入排序

简单插入排序

核心思想是将待排序的序列分为已排序序列和未排序序列。比如一个未排序序列,直接默认已排序序列只有第一个元素这种就行。C语言解释代码:

void InsertionSort(ElementType A[],int N){int i,j;ElementType temp;    for(i=0;i<N;i++){        temp=A[i];        for(j=i;(j<0)&&(temp<A[j-1]);j--){            A[j]=A[j-1];//将已排序元素大于当前temp的元素右移        }        A[j]=temp;//将当前的temp元素放入合适位置    }}

希尔排序

希尔排序是每次交换间隔一定距离的元素(比如1,3,6,4,5;取其中的1和4,就相当于间隔3;类似的直到间隔为1则完成了最终排序),C语言解释代码:

void ShellSort(ElementType A[],int N,int Incre[],int M){    //Incre[]为排序增量的数组,最后一个元素的值为1(说明排序完成)    int i,j;k,Increment;    ElementType temp;    for(i=0;i<M;i++){        Increment=Incre[i];//选择排序的增量        //进行一次增量排序        for(j=Increment;j<N;j++){            temp=A[j];            for(k=j;k-Increment>=0;k-=Increment){                if(temp>=A[k-Increment])break;                else                    A[k]=A[k-Increment];                A[k]=temp;              }        }    }}

交换排序

冒泡排序

最简单的交换排序,通过不断循环将最大或者最小元素交换出来,放到未排序元素的最后。C语言解释代码:

void BubbleSort(ElementType A[],int N){    int i,j;    bool flag;    ElementType temp;    for(i=N-1;i>=0;i--){        //初始时标记未交换        flag=0;        //循环找出最大元素放到最右端        for(j=0;i<i;j++){            if(A[j]>A[j+1]){                temp=A[j];                A[j]=A[j+1];                A[j+1]=temp;                //标记是否交换                flag=1;            }        }        if(!flag)break;//如果一次未发生交换说明有序,跳出循环    }}

快速排序

原理是将未排序的元素根据基准分为两个子序列,一个子序列均大于基准,另一个均小于基准,然后递归的对这两个子序列用类似方法排序。C语言解释代码:

//交换两个元素的值void Swap(ElementType *a,ElementType *b){    ElementType temp=*a;    *a=*b;    *b=temp;}void Qsort(ElementType A[],int Low,int High){    //以第一个元素为基准    ElementType Pivot=A[low];    //保存初始的最大最小元素位置    int Left=Low,Right=High;    if(Low>=High) return;    //基准先放到最后    Swap(&A[Low],&A[High]);    //将比基准小的移到基准左边,比基准大的移到基准右边    while(1){        while((Low<High)&&(Pivot>=A[Low])) Low++;        while((Low<High)&&(Pivot<=A[High])) High--;        if(Low<High)            Swap[&A[Low],&A[High]];        else break;    }    //基准回到中间    Swap(&A[Low],&A[High]);    //分别对左右两个边的序列继续快排    Qsort(A,Left,Low-1);    Qsort(A,low+1,Right);}//执行快排void QuikSort(ElementType A[],int N){    Qsort(A,0,N-1);}

归并排序

归并排序是指将两个已排序的子序列合成一个有序序列的过程。原理是:可以将大小为N的序列看成N个长度为1的子序列,然后两两归并,形成一个N/2长度的长度为2的子序列有序序列,然后继续将相邻的子序列两两归并,如此循环直到最后剩下一个长度为N的序列。

//将两个序列归并void merge(ElementType A[],ElementType TmpA[],int Left,int Mid,int Right){    int Tp,LeftEnd,i;    Tp=Left;    LeftEnd=Mid-1;    while((Left>LeftEnd)&&(Mid<Right)){        //如果左序列元素比右序列大,则将左边元素移入临时序列        if(A[Left]<=A[Mid])            TmpA[Tp++]=A[Left++];        else        //如果右序列元素比左序列大,则将右边元素移入临时序列            TmpA[Tp++]=A[Mid++];    }    while(Left<=LeftEnd)//满足说明右边序列元素已经没了        //将剩余的左边元素复制到临时序列        TmpA[Tp++]=A[Left++];    while(Mid<=Right)//满足说明左边序列元素已经都没了        //将剩余的右边元素复制到临时序列        TmpA[Tp++]=A[Mid++];    //将临时序列放回到A中    for(i=Right-Left;i>=0;i--,Right--){        A[Right]=TmpA[Right];    }}//递归排序void Msort(ElementType A[],ElementType TmpA[],int Left,int Right){    if(Left<Right){        Msort(A,TmpA,Left,(Left+Right)/2);        Msort(A,TmpA,(Left+Right)/2+1,Right);        merge(A,TmpA,Left,(Left+Right)/2,Right);    }}//排序方法(执行方法)void MergeSort(){    ElementType *TmpA;    TmpA=malloc(N*sizeof(ElementType));    Msort(A,TmpA,0,N-1);    free(TmpA);}

基数排序

基数排序可以看成桶排序。桶排序是将关键字的每个可能的取值建立一个桶,扫描所有序列元素,按照关键字放入对应的桶中,然后再按照桶的顺序收集一遍自然就有序。而基数排序属于桶排序的一种推广,所考虑的待排序记录的关键字不止一个。
对于一般有K个关键字的基数排序,通常有两种方法:主位优先法(MSD)和次位优先法(LSD)。
下面是次位优先法的C语言代码解释实现(有待研究):

typedef struct Node *PtrToNode;typedef PtrToNode List;struct Node{    int Key[MaxDigit];    PtrToNode Next;};List RadixSort(List A){    List Bucket[Radix];//建立Radix个桶    List Bear[Radix];//需要记录每个桶的链表的尾元素的位置    int i,j,Digit;    for(i=MaxDigit-1;i>=0;i--){//从最次关键字开始        for(j=0;j<Radix;j++)        Bucket[j]=Rear[j]=NULL;        while(A){//将关键字逐一分配到桶            Digit=A->Key[i];            if(!Bucket[Digit]){                Bucket[Digit]=A;            }else{                Rear[Digit]->Next=A;            }            Rear[Digit]=A;            A=A->Next;        }        for(j=Radix-1;j>=0;j--){            if(Bucket[j]){                Rear[j]->Next=A;                A=Bucket[j];            }        }    }    return A;}

各算法效率比较

排序方法 平均时间复杂度 最坏情况的时间复杂度 额外的空间复杂度 稳定性 简单选择排序 O(N2) O(N2) O(1) 不稳定 简单插入排序 O(N2) O(N2) O(1) 稳定 冒泡排序 O(N2) O(N2) O(1) 稳定 希尔排序 O(Nd) O(N2) O(1) 不稳定 堆排序 O(N log2N) O(N log2N) O(1) 不稳定 快速排序 O(N log2N) O(N2) O(log2N) 不稳定 归并排序 O(N log2N) O(N log2N) O(N) 稳定 基数排序 O(D(N+R)) O(D(N+R)) O(N+R) 稳定

注:
1、稳定是指是否在排序后改变原有等值元素的顺序。
2、基数排序中的D为分配收集的趟数,也就是关键字按基数分解后的位数

以上

参考文献:高等教育出版社出版的陈越主编的《数据结构》

0 0