排序算法初步总结

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

插入排序

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

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
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值