算法设计分析(二分归并排序)

1. 问题

二分归并排序:对n个不同的数构成的数组A[1..n]进行排序,其中n=2^k

2. 解析

二分归并排序采用了分治的思想,将序列不断划分成左右两个序列,然后依次将小序列进行排序,然后归并到大序列中。

3. 设计

void Mergesort(int l,int r)

{

    int mid = (l + r) >> 1;

    if(r - l + 1 <= 1)  // 如果序列长度<=1的话那么这个序列必然是有序的

    {

        return;

    }

    else if(r - l + 1 == 2) // 如果这个序列的长度 == 2 那么我们可以手动对这个序列进行排序

    {

        if(arr[r] < arr[l])

        {

            int t;

            t = arr[r];

            arr[r] = arr[l];

            arr[l] = t;

        }

    }

    else

    {

        Mergesort(l , mid);     

        Mergesort(mid + 1,  r); 

        // 当序列长度 > 2时,我们把序列分成两块,分别对序列的左子序列,和右子序列进行排序

        // 左右子序列排好序之后,我们需要把左右两个子序列归并成为一个有序序列

        int s1 = l , s2 = mid + 1;

        int s = l;

        while(s1 <= mid && s2 <= r) // 每次只取两个子序列中最小,这样来将两个子序列归并到一起

        {

            if(arr[s1] < arr[s2]) tmp[s++] = arr[s1++];

            else tmp[s++] = arr[s2++];

        }

        while(s1 <= mid) tmp[s++] = arr[s1++];

        while(s2 <= r) tmp[s++] = arr[s2++];

        for(int i = l ; i <= r; ++ i) arr[i] = tmp[i]; // 把排序好的tmp数组赋值给arr

    }

}

4. 分析

时间复杂度:O(nlogn)

解析:每次都将数列分成左右两个序列,每次归并的时候需要将元素复制到tmp数组中。又因为最多归并logn层,每层所需的时间是n。

空间复杂度:O(n)

解析:在归并的时候需要将元素赋值到tmp数组,因此需要另外开一个tmp数组,这个数组的大小 >= 存有数据的数组的大小。

4. 完整代码

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<stdlib.h>
 4 #include<math.h>
 5 #include<algorithm>
 6 #include<time.h>
 7 
 8 const int maxn = 1e5 + 100;    //
 9 
10 int arr[maxn] ,tmp[maxn];  // arr数组用于存储排序前和排序后的序列,tmp数组用于在二分归并排序的过程中使用
11 int n; // n 代表序列的长度
12 void Mergesort(int l,int r)
13 {
14     int mid = (l + r) >> 1;
15     if(r - l + 1 <= 1)  // 如果序列长度<=1的话那么这个序列必然是有序的
16     {
17         return;
18     }
19     else if(r - l + 1 == 2) // 如果这个序列的长度 == 2 那么我们可以手动对这个序列进行排序
20     {
21         if(arr[r] < arr[l])
22         {
23             int t;
24             t = arr[r];
25             arr[r] = arr[l];
26             arr[l] = t;
27         }
28     }
29     else
30     {
31         Mergesort(l , mid);     
32         Mergesort(mid + 1,  r); 
33         // 当序列长度 > 2时,我们把序列分成两块,分别对序列的左子序列,和右子序列进行排序
34         // 左右子序列排好序之后,我们需要把左右两个子序列归并成为一个有序序列
35         int s1 = l , s2 = mid + 1;
36         int s = l;
37         while(s1 <= mid && s2 <= r) // 每次只取两个子序列中最小,这样来将两个子序列归并到一起
38         {
39             if(arr[s1] < arr[s2]) tmp[s++] = arr[s1++];
40             else tmp[s++] = arr[s2++];
41         }
42         while(s1 <= mid) tmp[s++] = arr[s1++];
43         while(s2 <= r) tmp[s++] = arr[s2++];
44         for(int i = l ; i <= r; ++ i) arr[i] = tmp[i]; // 把排序好的tmp数组赋值给arr
45     }
46 }
47 
48 
49 int main()
50 {
51     srand(time(NULL));
52     scanf("%d",&n);
53     for(int i = 1 ; i <= n ; ++ i)
54     {
55         arr[i] = rand()%100 + 1; // 通过随机数生成数组元素
56     }
57     Mergesort(1 , n);
58     for(int i = 1 ; i <= n ; ++ i)
59     {
60         printf("%d ",arr[i]);
61     }
62     printf("
");
63     return 0;
64 }
二分归并排序
原文地址:https://www.cnblogs.com/DreamACMer/p/12555599.html