30、数据结构与算法 - 排序(二)归并排序

归并排序(Merging Sort)


是利用归并的思想实现排序方法,他的原理是假设初始序列含有n个记录,则可以看成n个有序的子序列,每个子序列的长度为1,然后两两合并,得到[n/2]个长度为2或1的有序子序列,再两两归并。 ……如此重复,知道得到一个长度为n的有序序列为止,这种排序方法称为2路归并排序

 

如上图,归并排序就是将序列,拆分成不大于2的序列,进行排序,然后再依次两两合并再排序,直到合并完成

归并

递归 与 非递归

 

代码实现

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef int Status;

//1.排序算法数据结构设计
//用于要排序数组个数最大值,可根据需要修改
#define MAXSIZE 10000
typedef struct
{
    //用于存储要排序数组,r[0]用作哨兵或临时变量
    int r[MAXSIZE+1];
    //用于记录顺序表的长度
    int length;
}SqList;

//2.排序常用交换函数实现
//交换L中数组r的下标为i和j的值
void swap(SqList *L,int i,int j)
{
    int temp=L->r[i];
    L->r[i]=L->r[j];
    L->r[j]=temp;
}

//3.数组打印
void print(SqList L)
{
    int i;
    for(i=1;i<L.length;i++)
        printf("%d,",L.r[i]);
    printf("%d",L.r[i]);
    printf("\n");
}
//11.归并排序-对顺序表L进行归并排序
//③ 将有序的SR[i..mid]和SR[mid+1..n]归并为有序的TR[i..n]
void Merge(int SR[],int TR[],int i,int m,int n)
{
    int j,k,l;
    //1.将SR中记录由小到大地并入TR
    for(j=m+1,k=i;i<=m && j<=n;k++)
    {
        if (SR[i]<SR[j])
            TR[k]=SR[i++];
        else
            TR[k]=SR[j++];
    }
    
    //2.将剩余的SR[i..mid]复制到TR
    if(i<=m)
    {
        for(l=0;l<=m-i;l++)
            TR[k+l]=SR[i+l];
    }
    
    //3.将剩余的SR[j..mid]复制到TR
    if(j<=n)
    {
        for(l=0;l<=n-j;l++)
            TR[k+l]=SR[j+l];
    }
}
//② 将SR[s...t] 归并排序为 TR1[s...t];
void MSort(int SR[],int TR1[],int low, int hight){
    int mid;
    int TR2[MAXSIZE+1];
    
    if(low == hight)
        TR1[low] = SR[low];
    else{
        //1.将SR[low...hight] 平分成 SR[low...mid] 和 SR[mid+1,hight];
        mid = (low + hight)/2;
        //2. 递归将SR[low,mid]归并为有序的TR2[low,mid];
        MSort(SR, TR2, low, mid);
        //3. 递归将SR[mid+1,hight]归并为有序的TR2[mid+1,hight];
        MSort(SR, TR2, mid+1, hight);
        //4. 将TR2[low,mid] 与 TR2[mid+1,hight], 归并到TR1[low,hight]中
        Merge(TR2, TR1, low, mid, hight);
    }
}
//① 对顺序表L进行归并排序
void MergeSort(SqList *L){
   
    MSort(L->r,L->r,1,L->length);
}

//12.归并排序(非递归)-->对顺序表L进行非递归排序
//对SR数组中相邻长度为s的子序列进行两两归并到TR[]数组中;
void MergePass(int SR[],int TR[],int s,int length){
  
    int i = 1;
    int j;
    
    //①合并数组
    //s=1 循环结束位置:8 (9-2*1+1=8)
    //s=2 循环结束位置:6 (9-2*2+1=6)
    //s=4 循环结束位置:2 (9-2*4+1=2)
    //s=8 循环结束位置:-6(9-2*8+1=-6) s = 8时,不会进入到循环;
    while (i<= length-2*s+1) {
        //两两归并(合并相邻的2段数据)
        Merge(SR, TR, i, i+s-1, i+2*s-1);
        i = i+2*s;
        
        /*
         s = 1,i = 1,Merge(SR,TR,1,1,2);
         s = 1,i = 3,Merge(SR,TR,3,3,4);
         s = 1,i = 5,Merge(SR,TR,5,5,6);
         s = 1,i = 7,Merge(SR,TR,7,7,8);
         s = 1,i = 9,退出循环;
         */
        
        /*
         s = 2,i = 1,Merge(SR,TR,1,2,4);
         s = 2,i = 5,Merge(SR,TR,5,6,8);
         s = 2,i = 9,退出循环;
         */
        
        /*
         s = 4,i = 1,Merge(SR,TR,1,4,8);
         s = 4,i = 9,退出循环;
         */
    }
    
    //②如果i<length-s+1,表示有2个长度不等的子序列. 其中一个长度为length,另一个小于length
    // 1 < (9-8+1)(2)
    //s = 8时, 1 < (9-8+1)
    if(i < length-s+1){
        //Merge(SR,TR,1,8,9)
        Merge(SR, TR, i, i+s-1, length);
    }else{
        //③只剩下一个子序列;
        for (j = i; j <=length; j++) {
            TR[j] = SR[j];
        }
    }
}
void MergeSort2(SqList *L){
    int *TR = (int *)malloc(sizeof(int) * L->length);
    int k = 1;
    //k的拆分变换是 1,2,4,8;
    while (k < L->length) {
        //将SR数组按照s=2的长度进行拆分合并,结果存储到TR数组中;
        //注意:此时经过第一轮的归并排序的结果是存储到TR数组了;
        MergePass(L->r, TR, k, L->length);
        k = 2*k;
        //将刚刚归并排序后的TR数组,按照s = 2k的长度进行拆分合并. 结果存储到L->r数组中;
        //注意:因为上一轮的排序的结果是存储到TR数组,所以这次排序的数据应该是再次对TR数组排序;
        MergePass(TR, L->r, k, L->length);
        k = 2*k;
        
    }
}
#define N 9
int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, 排序算法\n");
    
    int i;
    int d[N]={-7,1,5,8,3,7,4,6,2};
    //int d[N]={9,8,7,6,5,4,3,2,1};å
    //int d[N]={50,10,90,30,70,40,80,60,20};
    SqList l0,l1,l2,l3,l4,l5,l6,l7,l8,l9,l10;
   
    for(i=0;i<N;i++)
        l0.r[i+1]=d[i];
    
    l0.length=N;
    l1=l2=l3=l4=l5=l6=l7=l8=l9=l10=l0;
    
    printf("排序前:\n");
    print(l0);
    printf("\n");
    
    //8.归并排序(递归)
    printf("归并排序(递归):\n");
    MergeSort(&l7);
    print(l7);
    printf("\n");
    
    //9.归并排序(非递归)
    printf("归并排序(非递归):\n");
    MergeSort2(&l8);
    print(l8);
    printf("\n");
    
 
    printf("\n");
    return 0;
}
Hello, 排序算法
排序前:
-7,1,5,8,3,7,4,6,2

归并排序(递归):
-7,1,2,3,4,5,6,7,8

归并排序(非递归):
-7,1,2,3,4,5,6,7,8

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
排序是计算机科学中常见的操作,它将一组元素按照特定的顺序重新排列。排序算法的目标通常是将元素按照升序或降序排列。 常见的排序算法有很多种,每种算法都有不同的时间复杂度和空间复杂度。以下是几种常见的排序算法: 1. 冒泡排序(Bubble Sort):比较相邻的两个元素,如果顺序不正确就交换位置,每次遍历将一个最大(最小)的元素移到最后(最前)。时间复杂度为O(n^2)。 2. 插入排序(Insertion Sort):将数组分为已排序和未排序两部分,每次从未排序部分取出一个元素,插入已排序部分的适当位置。时间复杂度为O(n^2)。 3. 选择排序(Selection Sort):每次从未排序部分选择一个最小(最大)的元素放到已排序部分的末尾。时间复杂度为O(n^2)。 4. 快速排序(Quick Sort):选取一个基准元素,将数组划分为两个子数组,小于基准元素的放在左边,大于基准元素的放在右边,然后对子数组进行递归排序。时间复杂度平均情况下为O(nlogn),最坏情况下为O(n^2)。 5. 归并排序(Merge Sort):将数组递归分成两个子数组,然后对子数组进行排序,最后将两个已排序的子数组合并成一个有序数组。时间复杂度为O(nlogn)。 6. 堆排序(Heap Sort):将数组构建成一个最大(最小)堆,每次从堆顶取出最大(最小)元素放到已排序部分的末尾,然后调整堆使其满足堆的性质。时间复杂度为O(nlogn)。 这里只介绍了几种常见的排序算法,每种算法都有其适用的场景和优缺点。在实际应用中,根据数据规模和性能要求选择合适的排序算法非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值