文章标题

来源:互联网 发布:php 获得父类的属性 编辑:程序博客网 时间:2024/06/18 11:57

各种排序算法的分析

目录

  1. 选择排序

    • 简单选择排序
    • 堆排序
  2. 插入排序

    • 简单插入排序
    • 希尔排序
  3. 交换排序
    • 冒泡排序
    • 快速排序
  4. 归并排序
  5. 基数排序
  6. 各种排序性能分析

正文

1. 选择排序

1.1简单选择排序

首先在未排序的序列中选出最小的元素与序列的首元素交换,即为最小元素。再在剩余元素序列中选出最小的元素与第二个元素交换作为第二小的元素。依此类推,最后形成从小到大的序列。

void SimpleSelectionSort(ElemType A[],int N){    int i,j,min,temp;    for(i=0;i<N;i++){        min = i;        for(j=i+1;j<N;j++){            if(A[j]<A[min])                min=j;        }        temp = A[i];        A[i] = A[min];        A[min] = temp;    }}

1.2堆排序

将元素存在数组中,将数组调整为最大堆。之后将堆顶元素和堆末尾元素交换,堆大小减一。再将堆顶元素向下过滤调整为最大堆。重复交换和过滤步骤,直到堆大小为1。

void Adjust(ElemType A[], int i, int N){    //对A[]中的前N个元素从下标为i的元素开始向下迁移调整    int child;    ElemType temp;    for (temp = A[i];(2 * i + 1) < N;i = child) {    //寻找子节点中值最大的与temp比较,如果temp小,则将子节点上移        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(ElemType A[], int N){/*堆排序*/    int i;    ElemType temp;    /*建立最大堆*/    for (i = (N-2)/2;i >= 0;i--)    {//(N-2)/2是A[N-1]的父节点        Adjust(A, i, N);    }    for (i = N - 1;i > 0;i--) {        /*将堆顶元素A[0]与当前堆的最后一个元素A[i]换位*/        temp = A[0];A[0] = A[i];A[i] = temp;        /*将有i个元素的新堆从根节点向下过滤调整*/        Adjust(A, 0, i);    }}

2.插入排序

2.1简单插入排序

从第二个元素起,将该元素插入到它前面的有序序列中,同时保证有序。类似于扑克牌插牌。

void InsertionSort(ElemType A[],int N){    int i,j;    ElemType temp;    for(i=1;i<N;i++){        temp=A[i];        for(j=i-1;j>=0;j--){            if(A[j]>temp)                A[j+1]=A[j];            else break;        }        A[j+1]=temp;//放进合适的位置    }}

2.2希尔排序

希尔排序定义一组递减增量序列,首先以最大增量将无序序列划分成若干组,每一组进行插入排序。再以剩余的增量依次进行插入排序直到最后一个为1的增量。

void ShellSort(ElemType A[],int N,int Incre[],int M){//Incre[]为包含M个增量的的递减序列,且最后一个元素为1    int i,j;    int Increment,temp;    for(i=0;i<M;i++){        Increment = Incre[i];        for(j=Increment;j<N;j++){        //从A[Increment]开始,将它插入到它之前的所在Increment序列中。            temp=A[j];            for(k=j;k>=0;k-=Increment){                if(temp>=A[k-Increment) break;                else                    A[k]=A[k-Increment];            }            A[k]=temp;        }//结束第一趟排序    }}

3.交换排序

3.1冒泡排序

首先从第一个元素起,向后遍历到末元素过程中总是将当前元素与后一个元素比较,如果当前元素较大,则与后一个元素交换位置(小在前大在后)。这样一遍就把序列中的最大元素放在了末尾。

然后再从第一个元素起同样遍历到倒数第二个元素,依此类推,直到没有可以遍历的序列。

void BubleSort(ElemType A[],int N){    int i,j;    bool flag=false;    ElemType temp;    for(i=N-1;i>=0;i--){        for(j=0;j<i;j++){            if(A[j]>A[j+1]){                temp=A[j];                A[j]=A[j+1];                A[j+1]=temp;                flag=true;            }        }        if(flag=false) break;//原序列有序,跳出循环    }}

3.2快速排序

快速排序每一轮确定出指定序列中某一个元素(基准元素)所应该在的位置,然后将该元素左边、右边的序列分别进行排序。递归边界是排序序列只有一个元素

void Swap(ElemType *a,ElemType *b){    ElemType temp=*a;    *a=*b;    *b=temp;}void QSort(ElemType A[],int low,int high){    ElemType Pivot = A[low];    int left =low,right=high;    if(low>=high) return;    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[left]);    /*分别对两个子集进行快排*/    Qsort(A,left,low-1);    Qsort(A,low+1,right);}void QuickSort(ElemType A[],int N){    //快速排序    Qsort(A,0,N-1);}

4.归并排序

归并排序实质上是一种分治思想,将一个无序序列分成两半,左边归并排序为有序,右边归并排序为有序,然后将左、右两边序列进行归并。核心操作就是两个有序序列的归并操作。

void Merge(ElemType A[],ElemType A[],int Left,int Mid,int Right){//将有序的A[Left]-A[Mid-1]和A[Mid]-A[Right]归并    int Tp = left;    int LeftEnd,i;    int Len = Right-Left+1;//要归并序列的长度    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++]=TmpA[Left++];    while(Mid<=Right)        TmpA[Tp++]=TmpA[Mid++];    for(i=Len;i>0;i--,Right--){        A[Right]=TmpA[Right];    }}void MSort(ElemType A[],ElemType 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+1,Right);//归并    }}void MergeSort(ElemType A[],int N){    ElemType *TmpA;    TmpA=(ElemType*)malloc(N*sizeof(ElemType));//开辟临时空间    MSort(A,TmpA,0,N-1);//将A[0]-A[N-1]归并排序好,以TTmp[]作为辅助数组    free(TmpA);}

5.基数排序

多关键字的基数排序

如给定范围在0-999之间的10个关键字{64,8,216,512,27,729,0,1,343,125},现在用基数排序算法进行递增排序
把十进制整数关键字分解为3个关键字,其个位为最次位关键字,百位是最主位关键字。按照次位优先法进行排序。

typedef struct Node* PtrToNode;typedef PtrToNode List;struct Node{    int Key[MaxDigit];//Key[]存放该结点元素的百、十、个位    PtrToNode Next;};List RadixSort(List A){    List Bucket[Radix];//Radix个桶    List Rear[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]==NULL){//如果桶空                Bucket[Digit]=A;            }            else Rear[Digit]->Next=A;//否则放入桶链表尾部            Rear[Digit]=A;//更新尾指针            A=A->Next;//A指向下一个元素        }//结束while分配        for(j=Radix-1;j>=0;j--){//从尾部开始将各桶链表串联            if(Bucket[j]){                Rear[j]->Next=A;                A=Bucket[j];            }        }//结束串联    }    return A}

6.各种排序性能分析

排序方法 平均时间复杂度 最坏时间复杂度 额外空间复杂度 稳定性 简单选择排序 O(N^2) O(N^2) O(1) 不稳定 直接插入排序 O(N^2) O(N^2) O(1) 稳定 冒泡排序 O(N^2) O(N^2) O(1) 稳定 希尔排序 O(N^d) O(N^2) O(1) 不稳定 堆排序 O(NlogN) O(logN) O(1) 不稳定 快速排序 O(NlogN) O(N^2) O(logN) 不稳定 归并排序 O(NlogN) O(NlogN) O(N) 稳定 基数排序 O(D(N+R)),D是关键字个数,N是元素个数,R是桶个数 O(D(N+R)) O(N+R) 稳定