排序算法初步总结

来源:互联网 发布:%20是什么网络用语 编辑:程序博客网 时间:2024/05/23 18:45

       排序算法按照不同的原则可以分为不同的类。如根据排序的稳定性可以分为稳定排序和不稳定排序;根据排序过程所涉及到的存储器分为内部排序和外部排序等等。这里将根据排序采用的策略进行分类,可分为:插入排序、交换排序、选择排序、归并排序和基数排序等。

插入排序

  插入排序中最简单和基础的是直接插入排序和希尔排序。

1.直接插入排序

  基本思想:依次取出原始序列中元素,然后将其有序插入有序的序列中。

  特征:设置监视哨,其作用一方面是在循环中监视下标是否越界,省略了设置循环判断条件;另一方面在进入循环之前可以作为缓冲区域,这样可以保证记录的后移不会失去原值。

  code:时间复杂度O(n^2),空间复杂度O(1),稳定排序。

void InsertSort(NOde list[],int n){    int i,j;    for(i=1;i<n;i++){        list[0]=list[i]; //设置监视哨</span><span style="font-family:SimSun;font-size:14px;">list[0]</span><span style="font-size:18px;">        j=i-1;        while(list[0]<list[j]){//当前值小于前面的值,则记录后移,直到正确位置            list[j+1]=list[j];            j--;        }        list[j+1] = list[0];//找到正确位置后将list[0]的原记录值插入    }}


2.希尔排序

基本思想:又称为缩小增量排序,是对直接插入排序的一种改进排序。其先将整个待排序列分割成若干子序列,分别对子序列进行直接插入排序,等到整个序列中的记录基本有序时,再对整个序列进行一次直接插入排序。

特征:其对增量序列的选择没有严格要求,一般而言,对于n个序列,可以选择分组数依次为d1=n/2,d2=d1/2,d3=d2/2,...,di=1。

code:时间复杂度O(nlog2(n))-O(n^2),不稳定排序。

<span style="font-size:14px;">void ShellSort(NOde list[],int n){    int i,j,d;    for(d=n/2;d>0;d=d/2){//初始增量为n/2,每次缩小增量为d/2        for(i=d+1;i<=n;i++){            list[0]=list[i]; //设置监视哨            j=i-d;   //前后记录增量为d,而不是1            while(j>=0 && list[0]<list[j]){//当前值小于前面的值,则记录后移,直到正确位置                list[j+d]=list[j];                j-=d;            }            list[j+1] = list[0];//找到正确位置后将list[0]的原记录值插入        }    }}</span>

交换排序

  交换排序中最典型的两个是冒泡排序和快速排序。

1.冒泡排序

  基本思想:冒泡排序是最直观的一种排序方法,其排序过程中,相邻的两个元素进行比较,若前面的值大于后边的值则进行交换,否则则不交换。或者是较大值的前移。

  特征:设置中间变量,进行数据存储。

  code:时间复杂度O(n^2),稳定排序。

<span style="font-size:14px;">void Bubble_sort(NOde list[],int n){    int i,j,temp;    for(i=0;i<n;i++){        temp=0;  //交换标志变量,初始化为未交换        for(j=0;j<n;j++){            if(list[j]>list[j+1]){//前者大于后者则交换                list[0]=list[j+1];                list[j+1]=list[j];                list[j]=list[0];                temp=1;            }        }        if(temp==0) break; //未交换,排序结束    }}</span>

2.快速排序

基本思想:快速排序是对冒泡的一种改进,不同之处在于冒泡每次的比较和交换都是在相邻的单元进行的,只能左移或右移一个单元。而快排比较和交换式从两端向中间进行,大大减少了比较和移动的次数。

特征:任取序列中的某个数据作为基准线,通过一次的排序,将原始序列分为两个子序列,左子序列小于或等于该基准线,右子序列大于或等于该基准线,然后一次循环,直到最后排成有序序列。

code:时间复杂度O(nlog2(n)),不稳定排序。

int Partition(NOde list[],int low,int high){    list[0]=list[low];    while(low<high){        while(low<high && list[high]>=list[0])//在high端寻找一个比list[low]小的记录放入low            --high;        list[low]=list[high];        while(low<high && list[high]<=list[0])//在low端寻找一个比list[low]大的记录放入high            ++low;        list[high]=list[low];    }    list[low]=list[0];    return low;//返回基准线位置}void Quick_sort(NOde list[],int low,int high){    int loc;    if(low<high){        loc=Partition(list,low,high);//进行快排        Quick_sort(list,low,loc-1);//对前半区域进行划分        Quick_sort(list,loc+1,high);//对后半区域进行划分    }}


选择排序

  选择排序中分为简单选择排序和堆排序。

1.简单选择排序

  基本思想:顾名思义,即首先选择最小的数据放在第一个位置,再选取次小的数据放在第二个位置,以此类推,直至选出n-1个为止。

  特征:选取每次的最小值min。

  code:时间复杂度O(n^2),不稳定排序。

<span style="font-size:14px;">void Select_sort(NOde list[],int n){    int i,j,min;    for(i=0;i<n;i++){        min=i;        for(j=i+1;j<=n;j++){//在i-n的范围内寻找            if(list[min]>list[j])                min=j;            if(min!=j){                list[0]=list[min];                list[min]=list[i];                list[i]=list[0];            }        }    }}</span>

2.堆排序

基本思想:堆排序是利用堆特性进行排序的,根据其性质可知,堆的根为整个序列的最大值或最小值,因此将原始序列进行建堆,再对输出堆顶原始后进行维护,可以实现堆排序。

特征:建堆以及堆维护。

code:时间复杂度O(nlog2(n)),不稳定排序。

void Createtheap(NOde list[],int m,int n){    int i,j,flag;    i=m;j=2*i;    list[0]=list[i];    flag=0;    while(j<=n && flag!=1){//沿值较小的分支向下筛选        if(j<n && list[j]>list[j+1])//选取孩子中值较小的分支            j++;        if(list[0]<list[j])            flag=1;        else{//继续向下筛选            list[i]=list[j];            i=j;            j=2*i;            list[i]=list[0]        }    }}void Heap_sort(NOde list[],int n){    for(int i=n/2;i>=1;i--)//初始化堆        Createtheap(list,i,n);    for(int i=n;i>=1;i--){//list[1]为堆顶元素,可以设置循环输出        list[1]=list[i];//将堆尾元素移至堆顶        Createtheap(list,1,i);//整理堆    }}


归并排序

  归并排序可分为多路归并排序和二路归并排序。这里只对二路归并排序进行总结。

1.二路归并排序

  基本思想:将原始序列分为若干子序列,先将每个子序列进行排序,再将已排序的子序列进行合并,得到完整排序序列。

  特征:先将排序长度设置为1,然后两两归并为n/2个子序表,依次下去,直到长度为n的有序表。

  code:时间复杂度O(nlog2(n)),空间复杂度O(n),稳定排序。

<span style="font-size:14px;">void Merge(NOde a[],NOde b[],int i,int m,int n){    int la,lb,lc;    la=i;lb=m+1;lc=i;   //序列la,lb,lc的始点    while(la<=m && lb<=n){        if(a[la]<a[lb])   //有序合并            b[lc++] = a[la++];        else b[lc++] = a[lb++];    }    while(la<=m)   //复制第一个序列中剩下的元素        b[lc++] = a[la++];    while(lb<=n)  //复制第二个序列中剩下的元素        b[lc++] = a[lb++];}void MergPass(NOde list[],NOde A[],int n,int c){    int i=0,j;    while(i+2*c-1<=n-1){  //长度均为c的两个子序列合并为一个序列        Merge(list,A,i,i+c-1,i+2*c-1);        i+=2*c;    }    if(i+c-1<n)  //长度不相等的两个子序列合并为一个序列        Merge(list,A,i,i+c-1,n-1);    else  //只剩一个序列时直接复制到A中        for(j=i;j<=n-1;j++)            A[j]=list[j];}void Merge_sort(NOde list[],int n){    int c=1;  //初始归并长度为1    NOde A[MAXN];  //需要一个辅助空间    while(c<n){        MergPass(list,A,n,C);  //一次合并,结果写入A中        c*=2;   //序列长度扩大一倍        MergPass(A,list,n,C);  //再次合并,结果写入list中        c*=2;    }}</span>

其它排序

更新ing...


0 0
原创粉丝点击