【C语言】归并排序

简介: 【C语言】归并排序

一、什么是归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。

二、归并排序步骤图解

算法思想:

归并排序算法有两个基本的操作,,一个是分解,另一个是合并。分解是把原数组划分成两个子数组的过程,合并可以将两个有序数组合并成一个更大的有序数组。

将待排序的线性表不断地切分成若干个子表,直到每个子表只包含一个元素,这时,可以认为只包含一个元素的子表是有序表。将子表两两合并,每合并一次,就会产生一个新的且更长的有序表,重复这一步骤,直到最后只剩下一个子表,这个子表就是排好序的线性表。

示例图解步骤:

对如图的一个数组进行归并排序的步骤

三、归并排序代码实现

使用归并排序对一个数组a排序,需要另外创建一个数组tmp,用来存放有序子序列再放回去,具体过程如下

归并过程图解:

1、递归实现

//归并排序
void _MergeSort(int* a, int* tmp, int begin, int end)
{
  //递归结束条件
  if (begin >= end)
  {
    return;
  }
  int mid = (begin + end) / 2;
  _MergeSort(a, tmp, begin, mid);
  _MergeSort(a, tmp, mid+1, end);
  // 归并到tmp数据组,再拷贝回去
  int begin1 = begin;
  int end1 = mid;
  int begin2 = mid + 1;
  int end2 = end;
  int index = begin;
  //begin小于end说明还有两部分都还有数据
  while (begin1 <= end1 && begin2 <= end2)
  {
    if (a[begin1] < a[begin2])
    {
      tmp[index++] = a[begin1++];
    }
    else
    {
      tmp[index++] = a[begin2++];
    }
  }
  //由于右边没有数据跳出的上一个循环,将左边剩下的数放入tmp数组对应位置
  while (begin1 <= end1)
  {
    tmp[index++] = a[begin1++];
  }
  //由于左边没有数据跳出的上一个循环,将右边剩下的数放入tmp数组对应位置
  while (begin2 <= end2)
  {
    tmp[index++] = a[begin2++];
  }
  // 拷贝回原数组
  memcpy(a + begin, tmp + begin, (end - begin + 1) * sizeof(int));
}
void MergeSort(int* a, int n)
{
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
    perror("malloc fail");
    return;
  }
  _MergeSort(a, tmp, 0, n - 1);
  free(tmp);
}

2、非递归实现

非递归实现时当gap的值不同时有许多数组的数据个数不适合当前gap,访问就会越界,比如9个值时当gap==1就会访问到下标为9的下标越界,所以要在代码中加入解决措施。当第一组右边界越界,第二组左边界也一定越界了,所以可分为第二组左边界越界和第二组右边界越界两种情况处理。

//非递归归并
void MergeSortNonR(int* a, int n)
{
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
    perror("malloc fail");
    return;
  }
  int gap = 1;
  while (gap < n)
  {
    for (int i = 0; i < n; i += 2 * gap)
    {
      // 归并到tmp数据组,再拷贝回去
      int begin1 = i;
      int end1 = i + gap - 1;
      int begin2 = i + gap;
      int end2 = i + 2 * gap - 1;
      // 如果第二组不存在,这一组不用归并了
      if (begin2 >= n)
      {
        break;
      }
      // 如果第二组的右边界越界,修正一下
      if (end2 >= n)
      {
        end2 = n - 1;
      }
      int index = i;
      //begin小于end说明还有两部分都还有数据
      while (begin1 <= end1 && begin2 <= end2)
      {
        if (a[begin1] < a[begin2])
        {
          tmp[index++] = a[begin1++];
        }
        else
        {
          tmp[index++] = a[begin2++];
        }
      }
      //由于右边没有数据跳出的上一个循环,将左边剩下的数放入tmp数组对应位置
      while (begin1 <= end1)
      {
        tmp[index++] = a[begin1++];
      }
      //由于左边没有数据跳出的上一个循环,将右边剩下的数放入tmp数组对应位置
      while (begin2 <= end2)
      {
        tmp[index++] = a[begin2++];
      }
      // 拷贝回原数组
      memcpy(a + i, tmp + i, (end2 - i + 1) * sizeof(int));
    }
    gap *= 2;
  }
  free(tmp);
}

四、总结

归并排序的算法需要另外创建很大的空间,用来存放排序好的子表,然后再放回原线性表中,所以归并排序的空间复杂度比较大。

  • 归并排序时间复杂度为:O(N*logN)
  • 归并排序空间复杂度为:O(N)
  • 归并排序是稳定的排序
  • 归并排序属于外排序,在磁盘中进行
目录
相关文章
|
7月前
|
搜索推荐 C语言
【数据结构】—超级详细的归并排序(含C语言实现)
【数据结构】—超级详细的归并排序(含C语言实现)
|
6月前
|
算法 C语言
数据结构和算法——归并排序(有序子列的归并、递归算法、非递归算法、思路图解、C语言代码)
数据结构和算法——归并排序(有序子列的归并、递归算法、非递归算法、思路图解、C语言代码)
35 0
|
7月前
|
搜索推荐 C语言 C++
【排序算法】C语言实现归并排序,包括递归和迭代两个版本
【排序算法】C语言实现归并排序,包括递归和迭代两个版本
|
7月前
|
搜索推荐 C语言
【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)
【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)
47 0
|
7月前
|
算法 搜索推荐 C语言
C语言数据结构之排序整合与比较(冒泡,选择,插入,希尔,堆排序,快排及改良,归并排序,计数排序)
C语言数据结构之排序整合与比较(冒泡,选择,插入,希尔,堆排序,快排及改良,归并排序,计数排序)
|
7月前
|
存储 算法 搜索推荐
数据结构排序——详细讲解归并排序(c语言实现递归及非递归)
数据结构排序——详细讲解归并排序(c语言实现递归及非递归)
83 0
|
人工智能 算法 C语言
C语言归并排序
C语言归并排序
51 0
|
算法 搜索推荐 C语言
用C语言对学生成绩进行排序(归并排序和基数排序)
本文主要是使用C语言对学生成绩进行排序,使用的排序算法是归并排序和基数排序,含源码!
269 1
用C语言对学生成绩进行排序(归并排序和基数排序)
|
算法 搜索推荐 C语言
归并排序—C语言实现
归并排序—C语言实现
111 0
|
存储 搜索推荐 测试技术
数据结构__<八大排序> __插入排序 |希尔排序 |选择排序 |堆排序 |快速排序 |归并排序(C语言实现)
数据结构__<八大排序> __插入排序 |希尔排序 |选择排序 |堆排序 |快速排序 |归并排序(C语言实现)
279 0