排序算法-归并排序

本文深入讲解了归并排序算法的工作原理及其实现过程。通过详细解释如何将两个有序数组合并为一个有序数组,进而展示了如何利用分治策略实现整个数组的排序。文章提供了高效的归并排序代码实现,并对比了归并排序与其他排序算法的性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

首先考虑下如何将将二个有序数列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。

[cpp]  view plain  copy
 
  1. //将有序数组a[]和b[]合并到c[]中  
  2. void MemeryArray(int a[], int n, int b[], int m, int c[])  
  3. {  
  4.     int i, j, k;  
  5.   
  6.     i = j = k = 0;  
  7.     while (i < n && j < m)  
  8.     {  
  9.         if (a[i] < b[j])  
  10.             c[k++] = a[i++];  
  11.         else  
  12.             c[k++] = b[j++];   
  13.     }  
  14.   
  15.     while (i < n)  
  16.         c[k++] = a[i++];  
  17.   
  18.     while (j < m)  
  19.         c[k++] = b[j++];  
  20. }  

可以看出合并有序数列的效率是比较高的,可以达到O(n)。

解决了上面的合并有序数列问题,再来看归并排序,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?

可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。

[cpp]  view plain  copy
 
  1. //将有二个有序数列a[first...mid]和a[mid...last]合并。  
  2. void mergearray(int a[], int first, int mid, int last, int temp[])  
  3. {  
  4.     int i = first, j = mid + 1;  
  5.     int m = mid,   n = last;  
  6.     int k = 0;  
  7.       
  8.     while (i <= m && j <= n)  
  9.     {  
  10.         if (a[i] <= a[j])  
  11.             temp[k++] = a[i++];  
  12.         else  
  13.             temp[k++] = a[j++];  
  14.     }  
  15.       
  16.     while (i <= m)  
  17.         temp[k++] = a[i++];  
  18.       
  19.     while (j <= n)  
  20.         temp[k++] = a[j++];  
  21.       
  22.     for (i = 0; i < k; i++)  
  23.         a[first + i] = temp[i];  //敲黑板   划重点
  24. }  
  25. void mergesort(int a[], int first, int last, int temp[])  
  26. {  
  27.     if (first < last)  
  28.     {  
  29.         int mid = (first + last) / 2;  
  30.         mergesort(a, first, mid, temp);    //左边有序  
  31.         mergesort(a, mid + 1, last, temp); //右边有序  
  32.         mergearray(a, first, mid, last, temp); //可以直接将最上面函数写在这里,不用单独写一个函数了!//再将二个有序数列合并  
  33.     }  
  34. }  
  35.   
  36. bool MergeSort(int a[], int n)  
  37. {  
  38.     int *p = new int[n];  
  39.     if (p == NULL)  
  40.         return false;  
  41.     mergesort(a, 0, n - 1, p);  
  42.     delete[] p;  
  43.     return true;  
  44. }  

 

归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。

 

在本人电脑上对冒泡排序,直接插入排序,归并排序及直接使用系统的qsort()进行比较(均在Release版本下)

对20000个随机数据进行测试

 

对50000个随机数据进行测试:

 

再对200000个随机数据进行测试:

 

 

注:有的书上是在mergearray()合并有序数列时分配临时数组,但是过多的new操作会非常费时。因此作了下小小的变化。只在MergeSort()中new一个临时数组。后面的操作都共用这一个临时数组

java版本
 

public class SortArray {
    public static void mergeSort(int[] arr, int first, int last, int []temp) {
        if(first<last){
            int mid = (first+last)/2;
            mergeSort(arr, first, mid, temp);
            mergeSort(arr, mid+1, last, temp);
            int i =first,j=mid,m=mid+1,n=last,k=0;
            while(i<=j&&m<=n){
                if(arr[i]<arr[m]){
                    temp[k++]=arr[i++];
                }else{
                    temp[k++]=arr[m++];
                }
            }
            while(i<=j){
                temp[k++]=arr[i++];
            }
            while(m<=n){
                temp[k++]=arr[m++];
            }
            for(int ii=0;ii<k;ii++){
                arr[first+ii]=temp[ii];
            }
        }
    }

    public static void mergeSortAll(int[] arr) {
        if(null==arr)
            return;
        int size = arr.length;
        int [] temp = new int[size];
        mergeSort(arr, 0, size-1, temp);
    }

    public static void main(String[] args) {
        int[] arr = {4, 6, 3, 9, 1};
        mergeSortAll(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

 

c++版本

我自己写了代码1

//--------------------------------guibing-----------------------------

 

#include<iostream>
#include<fstream>
#include<vector>
#include<stack>
#include<queue>
 using namespace std;

 void mergesort(int a[], int first, int last, int temp[])
 {
if (first < last)
{
int mid = (first + last) / 2;
mergesort(a, first, mid, temp);    //左边有序  
mergesort(a, mid + 1, last, temp); //右边有序  
// mergearray(a, first, mid, last, temp); //再将二个有序数列合并  
int i = first, j = mid + 1, m = mid, n = last,k=0;
while (i <= m&&j <= n)
{
if (a[i] <= a[j])
{
temp[k++] = a[i++];
}
else
{
temp[k++] = a[j++];
}
}
while (i <= m)
temp[k++] = a[i++];
while (j <= n)
temp[k++] = a[j++];
for (i = 0; i < k; i++)
a[first + i] = temp[i];  //敲黑板   划重点
}
 }

 bool MergeSort(int a[], int n)
 {
int *p = new int[n];
if (p == NULL)
return false;
mergesort(a, 0, n - 1, p);
delete[] p;
return true;
 }

 int main()
 {
int a[5] = {5,5,1,3,2};
MergeSort(a, 5);
for (int i = 0; i < 5; i++)
cout << a[i] << " ";
 
system("pause");
return 0;
 }

 

 

我自己写了代码2

//--------------------------------guibing-----------------------------
void hebing(int a[], int l, int r, int k[])
{
    int mid = (l + r) / 2;
    int i = l; int j = mid + 1;
    int ki = 0;
    while (i <= mid&&j <= r)
    {
        if (a[i] < a[j])
        {
            k[ki] = a[i];
            ki++; i++;
        }
        else
        {
            k[ki] = a[j];
            ki++; j++;
        }
    }
    if (i <= mid)
    {
        while (i <= mid)
        {
            k[ki] = a[i];
            ki++; i++;
        }
    }
    if (j <= r)
    {
        while (j <= r)
        {
            k[ki] = a[j];
            ki++; j++;
        }
    }
    for (int ii = 0; ii < ki; ii++)
    {
        a[l+ii] = k[ii];
    }
}

void gbcore(int a[], int l, int r, int k[])
{
    if (l < r)
    {
        int mid = (l + r) / 2;
        gbcore(a, l, mid, k);
        gbcore(a, mid + 1, r, k);
        hebing(a, l, r, k);
    }
    
}
void gb(int a[], int size)
{
    int l = 0, r = size - 1;
    int *k = new int[size];
    gbcore(a, l, r, k);
    delete[] k;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值