几种排序算法

来源:互联网 发布:常熟淘宝村 编辑:程序博客网 时间:2024/05/01 13:55

本帖依据学习进度持续更新

《数据结构与算法分析-c语言描述》学到第七章,是时候该系统的学习一下排序算法了。首先学到的是插入排序,算法就不赘述了,书上博客上到处都有。书上的两个定理还不太明白:

插入排序

定理7.1

N个互异数的数组的平均逆序数是N(N-1)/4。

定理7.2

通过交换相邻元素进行排序的任何算法平均需要Ω(N^2)时间。

插入排序的算法复杂度应该为O(N^2)才对。

下面是我的测试用例:

void insertionSort(elementType A[], int N){Int j, P;elementType Tmp;for(P = 1; P < N; P++){Tmp = A[P];for(j = P; j > 0 && A[j – 1] > Tmp; j--)A[j] = A[j – 1];A[j] = Tmp;}}

希尔排序

希尔排序的最后一样增量是1,所以是直接插入排序,但移动次数比直接插入排序少,代入数组测试:

#include<stdio.h>#define elementType intvoid shellSort(elementType A[], int N){    int i, j, Increment;    elementType Tmp;       for(Increment = N/2; Increment > 0; Increment /= 2)        for(i = Increment; i < N; i++)        {            Tmp = A[i];            for(j = i; j >= Increment && Tmp < A[j-Increment]; j -= Increment)                A[j] = A[j-Increment];            A[j] = Tmp;        }}void main(){    int i;    int a[] = {81,94,11,96,12,35,17,95,28,58,41,75,15};    shellSort(a, 13);    for(i = 0; i < 13; i++)        printf("%d ", a[i]);}

堆排序

我们为了找出一列数第K个最小的数引入二叉堆,最小堆总能从根节点输出最小值,一直使用deleteMin函数就能输出一列排序好的数,因为最小值最先输出,所以这个数列是递减的。由此我们可以得出如果建一个最大堆,使用deleteMax函数就能输出一列递增的序列。时间复杂度为O(NlogN)。

#include<stdio.h>#define leftChild(i) (2*i+1)void Swap(int *a, int *b){int Tmp = *a;*a = *b;*b = Tmp;}void percDown(int A[], int i, int N){int Child, Tmp;for(Tmp = A[i]; leftChild(i) < N; i = Child){Child = leftChild(i);if(Child != N-1 && A[Child + 1] > A[Child])Child++;if(A[Child] > Tmp)A[i] = A[Child];elsebreak;}A[i] = Tmp;}void heapSort(int A[], int N){int i;for(i = N / 2; i >= 0; i--)percDown(A, i, N);for(i = N - 1; i > 0; i--){Swap(&A[0], &A[i]);percDown(A, 0, i);}}void main(){int i;int a[] = {81,94,11,96,12,35,17,95,28,58,41,75,15}; heapSort(a, 13);for(i = 0; i < 13; i++)printf("%d ", a[i]);}


归并排序

该算法是经典的分治策略,基本的操作是合并两个已排序的表,放到第三个表中。而已排序的表又可以通过归并排序本身递归得到。

#include<stdio.h>#include<stdlib.h>#define elementType intvoid Merge(elementType A[], elementType Tmp[], int Lpos, int Rpos, int rightEnd){    int i, leftEnd, numElements, Tmppos;    leftEnd = Rpos - 1;    Tmppos = Lpos;    numElements = rightEnd - Lpos + 1;    while(Lpos <= leftEnd && Rpos <= rightEnd)        if(A[Lpos] <= A[Rpos])            Tmp[Tmppos++] = A[Lpos++];        else            Tmp[Tmppos++] = A[Rpos++];    while(Lpos <= leftEnd)        Tmp[Tmppos++] = A[Lpos++];    while(Rpos <= rightEnd)        Tmp[Tmppos++] = A[Rpos++];    for(i = 0; i < numElements; i++, rightEnd--)        A[rightEnd] = Tmp[rightEnd];}void Msort(elementType A[], elementType Tmp[], int Left, int Right){    int Center;    if(Left < Right)    {        Center = (Left + Right) / 2;        Msort(A, Tmp, Left, Center);        Msort(A, Tmp, Center + 1, Right);        Merge(A, Tmp, Left, Center + 1, Right);    }}void mergeSort(elementType A[], int N){    elementType *Tmp;    Tmp = malloc(N * sizeof(elementType));    if(Tmp != NULL)    {        Msort(A, Tmp, 0, N - 1);        free(Tmp);    }    else        printf("No space for Tmp array");}void main(){    int i;    int a[] = {81,94,11,96,12,35,17,95,28,58,41,75,15};    mergeSort(a, 13);    for(i = 0; i < 13; i++)        printf("%d ", a[i]);}    



快速排序

书上的一种以三数中值作为基准值的快速排序,当数组长度小于3的时候选用插入排序,用的递归实现。

#include<stdio.h>#define Cutoff 3void Swap(int *a, int *b){    int Tmp = *a;    *a = *b;    *b = Tmp;}void insertionSort(int A[], int N){     int tmp;     int j, p;     for( p = 1; p < N; p++ )     {         tmp = A[p];         for( j = p; j > 0 && A[j -1] > tmp; j -- )             A[j] = A[j-1];         A[j] = tmp;     } }int Median3(int A[], int Left, int Right){int Center = (Left + Right) / 2; if(A[Left] > A[Center])Swap(&A[Left], &A[Center]);if(A[Left] > A[Right])Swap(&A[Left], &A[Right]);if(A[Center] > A[Right])Swap(&A[Center], &A[Right]); Swap(&A[Center], &A[Right - 1]);return A[Right - 1];}void Qsort(int A[], int Left, int Right){    int i, j, Pivot; if(Left + Cutoff <= Right)    {i = Left;j = Right - 1;Pivot = Median3(A, Left, Right);for(; ; ){while(A[++i] < Pivot){}while(A[--j] > Pivot){}if(i < j)Swap(&A[i], &A[j]);elsebreak;}Swap(&A[i], &A[Right - 1]); Qsort(A, Left, i - 1);Qsort(A, i + 1, Right);}elseinsertionSort(A + Left, Right - Left + 1);}void quickSort(int A[], int N){    Qsort(A, 0, N - 1);}void main()  {      int i;      int a[] = {81,94,11,96,12,35,17,95,28,58,41,75,15};       quickSort(a, 13);      for(i = 0; i < 13; i++)          printf("%d ", a[i]);  }

下面是自己写的以第一个数作为基准值的快速排序。实际上这中基准值的选取是非常糟糕的,如果输入是预排序的或是反序的,第一次分割就总是分割到一边,时间复杂度为O(N^2),仅作为编程练习。

#include<stdio.h>#define Cutoff 3void Swap(int *a, int *b){    int Tmp = *a;    *a = *b;    *b = Tmp;}void Qsort(int A[], int Left, int Right){    int i, j, Pivot; <span style="white-space:pre"></span>if(Left < Right)    {Pivot = A[Left];i = Left;j = Right - 1;Swap(&A[Left], &A[Right]);while(i <= j){while(A[i] < Pivot)i++;while(A[j] > Pivot)j--;if(i < j){Swap(&A[i], &A[j]);i++;j--;}elsebreak;}Swap(&A[i], &A[Right]);Qsort(A, Left, i - 1);Qsort(A, i + 1, Right);}}void quickSort(int A[], int N){    Qsort(A, 0, N - 1);}void main()  {      int i;      int a[] = {81,94,11,96,12,35,17,95,28,58,41,75,15};       quickSort(a, 13);      for(i = 0; i < 13; i++)          printf("%d ", a[i]);  }
//以第一个元素作为基准,单向划分的快速排序#include<stdio.h>void Swap(int *a, int *b){    int Tmp = *a;    *a = *b;    *b = Tmp;}void Qsort(int A[], int Left, int Right){    int i, j, Pivot;     if(Left >= Right)        return;    Pivot = A[Left];    int pos = Left;    for(i = Left+1; i <= Right; ++i)    {if(A[i] < Pivot)    Swap(&A[++pos], &A[i]);    }    Swap(&A[pos], &A[Left]);    Qsort(A, Left, pos - 1);    Qsort(A, pos + 1, Right);}void quickSort(int A[], int N){    Qsort(A, 0, N - 1);}









0 0
原创粉丝点击