基础算法(排序)

来源:互联网 发布:php从入门到精通下载 编辑:程序博客网 时间:2024/06/07 16:23

1. 简单选择排序。

排序原理:每次选择数组中最小的元素放在数组开头,多次循环完成排序。

例如:数组 [3,7,2,9,3,1,0,6] 的排序过程:

[3       7       2       9       3       1       0       6]

[3       7       2       9       3       1      0       6](寻找最小元素)

[0       7       2       9       3       1       3       6](交换)

0        [7      2       9       3       1       3       6](寻找最小元素)

0        [1      2       9       3       7       3       6](交换)

… …

0        1       2       3       3       6       7       9

 

程序如下:

#include <stdio.h>#define INF 0xffff//输出数组void outputArray(int test[],int length){    int i;    //printf("%d ",sizeof(test)/sizeof(int));    for(i=0;i<length;i++)    {        printf("%d ",test[i]);    }    printf("\n");}//交换两个数void swap_num(int &a,int &b){    int temp=b;    b=a;    a=temp;}//简单选择排序void simpleSort(int test[],int length){    int i,j;    for(i=0;i<length-1;i++)    {        int min_j=i+1;        for(j=i+1;j<length;j++)        {            if(test[j]<test[min_j])            {                min_j=j;            }        }        if(test[i]>test[min_j])        {            swap_num(test[i],test[min_j]);        }    }}int main(){    int test[]={3,7,2,9,3,1,0,6};    int length=sizeof(test)/sizeof(int);    printf("排序前:");    outputArray(test,length);    printf("排序后:");    simpleSort(test,length);    outputArray(test,length);    return 0;}

复杂度分析:

由于使用了2个for循环,时间复杂度为O(n^2);排序的时候是在数组内部进行,空间复杂度为O(1)。由于是交换排序,所以排序过程是不稳定的。


2. 冒泡排序。

排序原理:依次比较两个相邻的元素,如果顺序不对就交换。重复以上步骤,直到没有可以交换的元素为止。

例如:数组 [3,7,2,9,3,1,0,6] 的排序过程:

[3       7       2       9       3       1       0       6]

[3       2       7       9       3       1       0       6]

[3       2       7       9       3       1       0       6]

[3       2       7       3       9       1       0       6]

[3       2       7       3       1       9       0       6]

[3       2       7       3       1       0       9       6]

[3       2       7       3       1       0       6       9](第一轮排序完成)

[2       3       3       1       0       6       7       9](第二轮排序完成)

[2       3       1       0       3       6       7       9](第三轮排序完成)

[2       1       0       3       3       6       7       9](第四轮排序完成)

[1       0       2       3       3       6       7       9](第五轮排序完成)

[0       1       2       3       3       6       7       9](第六轮排序完成)

 

程序如下:

//冒泡排序void bubbleSort(int test[],int length){    int flag=1,i;    while(flag){        flag=0;        for(i=0;i<length-1;i++){            if(test[i]>test[i+1]){                flag=1;                swap_num(test[i],test[i+1]);            }        }        //outputArray(test,length);    }}

复杂度分析

两层循环,时间复杂度O(n^2),空间复杂度O(1),由于冒泡排序始终保证小元素在大元素前面,所以是稳定的排序。


3. 插入排序。

排序原理:创建一个空数组,遍历排序数组的每个元素,使其插入到创建数组的合理位

置,完成排序。

例如:数组[3,7,2,9,3,1,0,6] 的排序过程:

[3]      [7      2       9       3       1       0       6]

[3       7]      [2      9       3       1       0       6]

[2       3       7]      [9      3       1       0       6]

… …

[0       1       2       3       3       6       7       9]

 

插入的详细过程如下:

[1       5       8       9]      [4]

首先让4和9比较,如果4<9,两者交换位置;4再和8比较,两者交换位置;4再和5比较,两者交换位置;4和1比较,4>1,跳出循环,插入过程结束。

 

程序如下:

void insertSort(int test[],int length){    int i,j,pos,num;    for(i=1;i<length;i++){        //寻找插入的位置的同时,让数组元素右移        j=i-1;        pos=i;  //pos记录当前test[i]的位置        num=test[i];   //记录要插入的值        while(num<test[j] && j>=0){            test[pos]=test[j];            pos=j;            j--;        }        test[pos]=num;    }}



4. 希尔排序。

排序原理:希尔排序是基于插入排序的方法;通过增量delta将序列分成几个小序列,通过插入排序使小序列有序;当delta=1时,完成排序后即完成了最终排序。

例如:数组[3,7,2,9,3,1,0,6] 的排序过程:

当delta=4时,数组分为4组,如下所示:


每一组进行插入排序,得到结果:[3  1     0       6       3       7       2       9]

当delta=2时,数据分为2组,如下所示:


每一组进行插入排序,得到结果: [0         1       2       6       3       7       3       9]

当delta=1时,完成排序,结果为:[0         1       2       3       3       6       7       9]

 

程序如下:

#include <stdio.h>//输出数组void outputArray(int test[],int length){    int i;    for(i=0;i<length;i++)    {        printf("%d ",test[i]);    }    printf("\n");}void insertSort(int test[],int length,int delta){    int i,j,k,pos,num;    //有k个子序列    for(k=0;k<delta;k++){        for(i=k+delta;i<length;i+=delta){            j=i-delta;            pos=i;            num=test[i];            while(num<test[j] && j>=0){                test[pos]=test[j];                pos=j;                j-=delta;            }            test[pos]=num;        }    }    outputArray(test,length);}void shellSort(int test[],int length,int delta[],int delta_length){    for(int i=0;i<delta_length;i++){        insertSort(test,length,delta[i]);    }}int main(){    int test[]={3,7,2,9,3,1,0,6};    //设置增量数组    int delta[]={4,2,1};    int length=sizeof(test)/sizeof(int);    int delta_length=sizeof(delta)/sizeof(int);    printf("排序前:");    outputArray(test,length);    printf("排序后:");    shellSort(test,length,delta,delta_length);    return 0;}

一般认为希尔排序的时间复杂度为O(n^1.5),适用于中规模序列排序。希尔排序是不稳定的排序。


5. 归并排序。

排序原理:运用了分治法的思想,把序列平均分成两段,把两段分别进行排序,再把排

好的两段合在一起。对于子段排序时,递归调用上面的过程。

例如:数组[3,7,2,9,3,1,0,6] 的排序过程:

[3       7       2       9]      [3      1       0       6]      分组

[3       7]      [2      9]      [3      1]      [0      6]      递归分组

[3       7]      [2      9]      [1      3]      [0      6]      排序

[2       3       7       9]      [0      1       3       6]      合并

[0       1       2       3       3       6       7       9]      再合并,得到排序结果

 

合并的原理:设置两个指向子序列开始位置的指针,再建立一个空数组。让两个指针指

向的值进行比较,较小的值进入数组,指向较小数的指针加1,指

向下个位置。重复以上步骤,直到所有元素进入数组。

程序如下:

#include <stdio.h>//输出数组void outputArray(int test[],int length){    int i;    for(i=0;i<length;i++)    {        printf("%d ",test[i]);    }    printf("\n");}//将test数组的一部分进行归并排序void mergeSort(int test[],int beginIndex,int endIndex,int length){    //printf("调用函数mergeSort(test,%d,%d);\n",beginIndex,endIndex);    int LL=endIndex-beginIndex+1;    int mid=(beginIndex+endIndex)/2;    if(LL==2){        if(test[beginIndex]>test[endIndex]){            int TT=test[beginIndex];            test[beginIndex]=test[endIndex];            test[endIndex]=TT;        }    }    else if(LL>2){        mergeSort(test,beginIndex,mid,length);        mergeSort(test,mid+1,endIndex,length);        //合并的过程        int i=beginIndex;        int j=mid+1;        int k=0;        int* temp=new int[LL];        while(i<=mid && j<=endIndex){            if(test[i]<=test[j]){                temp[k]=test[i];                k++;i++;            }            else{                temp[k]=test[j];                k++;j++;            }        }        while(i<=mid){            temp[k]=test[i];            k++;i++;        }        while(j<=endIndex){            temp[k]=test[j];            k++;j++;        }        //将temp写回test        int ii,jj;        for(ii=beginIndex,jj=0;ii<=endIndex;ii++,jj++){            test[ii]=temp[jj];        }    }    //outputArray(test,length);}int main(){    int test[]={3,7,2,9,3,1,0,6};    int length=sizeof(test)/sizeof(int);    printf("排序前:\n");    outputArray(test,length);    printf("排序后:\n");    mergeSort(test,0,length-1,length);    outputArray(test,length);    return 0;}


6. 快速排序。

排序原理:选择一个初始元素a,利用算法将数组分为两段:比a小,比a大。将比a

小的元素放在a前面,比a大的元素放在a的后面。再使用递归对前后两段进行

如下操作,当每段元素只有2个或3个时,就停止上面操作,排序完成。

   分组原理:假设序列为r[left],r[left+1],… … ,r[right],设置两个指针i和j,指向left和right。

           x=r[left];反复执行以下操作使得i,j相遇。

           ①j向左扫描,直到r[j]<x,r[i]=r[j],r[j]置为空;

           ②i向右扫描,直到r[i]>x,r[j]=r[i],r[i]置为空。

例如:数组[3,7,2,9,3,1,0,6] 的分组排序过程:

[(3)    7       2       9       3       1       0      6]

[*       7       2       9       3       1     0       6]

[0       7       2       9       3       1      *       6]

[0       7       2       9       3       1      *       6]

[0       *       2       9       3       1      7       6]

[0       *       2       9       3       1       7       6]

[0       1       2       9       3       *       7       6]

[0       1       2       9       3      *       7       6]

[0       1       2       *       3       9       7       6]

[0       1       2       *       3       9       7       6]

[0       1       2]      [3]    [3      9       7       6](一趟排序完成)

#include <stdio.h>#define NAN -1//输出数组void outputArray(int test[],int length){    int i;    //printf("%d ",sizeof(test)/sizeof(int));    for(i=0;i<length;i++)    {        printf("%d ",test[i]);    }    printf("\n");}//快速分组int quickClassify(int test[],int left,int right){    int i=left;    int j=right;    int x=test[left];    while(i<j)    {        while(test[j]>=x && i<j)            j--;        test[i]=test[j];test[j]=NAN;        if(i>=j)  break;        i++;        while(test[i]<=x && i<j)            i++;        test[j]=test[i];test[i]=NAN;        if(i>=j)  break;        j--;    }    test[i]=x;    //printf("last  i=%d,j=%d\n",i,j);    return i;}//快速排序void quickSort(int test[],int left,int right){    if(left<right){        int n=quickClassify(test,left,right);        quickSort(test,left,n-1);        quickSort(test,n+1,right);    }}int main(){    int test[]={3,7,2,9,3,1,0,6};    int length=sizeof(test)/sizeof(int);    printf("排序前:");    outputArray(test,length);    printf("排序后:");    quickSort(test,0,length-1);    outputArray(test,length);    return 0;}

 快速排序的最好情况是每趟将序列分成两半,正好在表中间,时间复杂度O(nlogn);快速排序最坏的情况是已经排好序,时间复杂度O(n^2)。快速排序是不稳定的排序。


7. 堆排序。

排序原理:首先介绍大根堆和小根堆:一颗二叉树,如果它的所有子节点都比它们的父节点小;通过构建大根堆和小根堆可以求出序列的最大值或最小值。

排序原理:将序列看成是一颗二叉树。构建大根堆,求出序列的最大值,与序列尾部元素交换位置;再求出剩下元素的最大值。重复以上步骤,直到得到一个从小到大的序列。

例如:数组[3,7,2,9,3,1,0,6] 的分组排序过程:

 


将序列看成是一棵二叉树,整个排序分为两个部分:新建堆,将最大元与最后元素转换后的重建堆。

程序如下:

#include <stdio.h>void sift(int test[],int k,int m)//假设test[k..m]是以r[k]为根的完全二叉树{    int temp=test[k];    int x=test[k];    //保存当前调整的值    int i=k;    int j=2*i;    int finished=0;    while(j<=m && !finished){        if(j<m && test[j]<test[j+1])            j++;        if(x>=test[j])            finished=1;        else{            test[i]=test[j];   //向上移            i=j;            j=2*i;        }    }    test[i]=temp;}void create_heap(int test[],int length){    int i;    for(i=length/2-1;i>=0;i--){        sift(test,i,length-1);    }}void heapSort(int test[],int length){    int i;    create_heap(test,length);    for(i=length-1;i>=1;i--){        int temp=test[0];        test[0]=test[i];        test[i]=temp;        sift(test,0,i-1);    }}//输出数组void outputArray(int test[],int length){    int i;    //printf("%d ",sizeof(test)/sizeof(int));    for(i=0;i<length;i++)    {        printf("%d ",test[i]);    }    printf("\n");}int main(){    int test[]={3,7,2,9,3,1,0,6};    int length=sizeof(test)/sizeof(int);    printf("排序前:");    outputArray(test,length);    printf("排序后:");    heapSort(test,length);    outputArray(test,length);    return 0;}

堆排序时间复杂度在最好和最坏的情况下都是 ;堆排序是不稳定的排序。

 




  




0 0
原创粉丝点击