当前位置:   article > 正文

归并排序算法详解(c++ 版 递归实现)_归并排序c++

归并排序c++


一、归并排序(递归实现)的算法思想简介

一、将长度为n序列 递归拆解成n/2 个子序列 进行两两排序(递归归并左边的子序列,递归归并右边的子序列) 直到得到n个长度为1的自然有序序列为止
二、将两个已排序的子序列进行排序合并 直到有序序列的的长度为n 结束
三、图解如下:
在这里插入图片描述
在这里插入图片描述

二、排序过程的详解

1.将长度为n序列 递归拆解

  • 假设有序列初始值为: {5,4,6,3,1,2,8,7,10}; int arr[] = {5,4,6,3,1,2,8,7,10};
  • 取中间分解点 int mid = (height+low)/2 。其中:low 为序列的起始下标 hight 为结束下标 分解点取他们中间的点
  • 递归排序 arr[low] 至 arr[mid] 区间的序列 (原序列的左侧部分)
  • 递归排序 arr[mid+1] 至 arr[hight ] 区间的序列 (原序列的右侧部分)
  • 将左边的有序的子序列 和 右边的有序子序列 排序后组合 逐个填写到原数组中(这个部分的详细内容看第二点)
  • 直到被分解的子序列长度为1 的时候 自然有序 停止递归
  • 代码如下:
/**
 *功能:拆分有序的序列两两排序-拆解结束的条件 子序列长度为1的时候
 */
void sortArr(int arr[], int low, int hight) {
	if (low < hight) {
		int mid = (hight + low) / 2;
		sortArr(arr,low,mid);// 递归拆解左边的序列
		sortArr(arr, mid + 1, hight);// 递归拆解左边的序列
		mergeArr(arr, low, mid, hight);// 将两个有序的子序列(arr[low至mid]、arr[mid+1至hight] 排序合并成一个新的有序列
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

实际上当他们拆分成1个有序的子序列的时候才开始调用mergeArr 进行排序 合并 然后得到新的有序的序列(长度为2)然后返回上一层得再进行排序

2.合并排序

  • 首先要确定要排序两个有序的子序列的范围 所以 我们要传入low、mid、hight 来加以确定
  • 得出 arr[low] 至 arr[mid] 为第一个有序的子序列的范围 arr[mid+1] 至 arr[hight] 为第二个有序的子序列范围
  • 定义两个变量 int i; int j; 分别指向第一个和第二个有序子序列的开始部分 如下图所示 假设 此时待合并排序的第一个有序的子序列为 1,3,4,5,6 第二个有序的子序列为2,7,8,10 则变量i 指向的是1 变量j 指向的是 2 如下图所示(这个图是由博主自己画的有点渣渣 别介意)

在这里插入图片描述

  • 定义一个指向长度为hight-low+1的数组的指针 int* tempArr = new int[hight - low + 1];
  • 定义一个初始变量k 初始值为0 记录tempArr的实际长度即tempArr 目前有几条数据
  • 假设排序是从小到大的排序
  • 循环比较 有序的子序列 arr[low] 至 arr[mid] 以及 arr[mid+1] 至 arr[hight] 的值 最小的部分存入 tempArr 中
  • 当i 超过第一个序列的边界的的时候 或则j 大于第二个序列的编辑的时候停止比较
  • 如果i<=mid 意味着 arr[low] 到 arr[mid] 区间中的数组还没有比较完成 ,则直接把剩余的元素(arr[i]至arr[mid])复制到tempArr 中
  • 如果j<=hight意味着 arr[mid+1] 到 arr[hight] 区间中的数组还没有比较完成 ,则直接把剩余的元素(arr[j]至arr[hight])复制到tempArr 中 相关代码如下:
- int i = low, j = mid + 1, k = 0;
	while (i <= mid && j <= hight) {
		if (arr[i] < arr[j]) {
			tempArr[k] = arr[i];
			i++;
		}
		else {
			tempArr[k] = arr[j];
			j++;
		}
		k++;
	}
	// 如果 arr[low] 到 arr[mid] 区间中的数组还没有比较完成 ,直接复制到tempArr 中
	while (i <= mid) {
		tempArr[k] = arr[i];
		i++;
		k++;
	}
	// 如果 arr[mid+1] 到 arr[hight] 区间中的数组还没有比较完成 ,直接复制到tempArr 中
	while (j <= hight) {
		tempArr[k] = arr[j];
		j++;
		k++;
	}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 最后一步 将合并后的数组 tempArr 逐个赋值到 arr 数组中 赋值的范围为 low -hight因为子序列在arr 的范围是low-hight 所以arr 可变动的范围就是 arr[low]-arr[hight]
  • 合并函数的完整代码如下:
void mergeArr(int arr[], int low, int mid, int hight) {
	int* tempArr = new int[hight - low + 1];
	int i = low, j = mid + 1, k = 0;
	while (i <= mid && j <= hight) {
		if (arr[i] < arr[j]) {
			tempArr[k] = arr[i];
			i++;
		}
		else {
			tempArr[k] = arr[j];
			j++;
		}
		k++;
	}
	// 如果 arr[low] 到 arr[mid] 区间中的数组还没有比较完成 ,直接复制到tempArr 中
	while (i <= mid) {
		tempArr[k] = arr[i];
		i++;
		k++;
	}
	// 如果 arr[mid+1] 到 arr[hight] 区间中的数组还没有比较完成 ,直接复制到tempArr 中
	while (j <= hight) {
		tempArr[k] = arr[j];
		j++;
		k++;
	}
	// 比较完成之后 将原本的数组arr 下标 low-hight 对应的内容 进行改变
	i = low;
	for (int tempK = 0;((tempK < k)&&(i<=hight));tempK++) {
		arr[i] = tempArr[tempK];
		i++;
	}
	delete[] tempArr;
	tempArr = NULL;
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

三、 归并排序代码详情

归并代码实际上就是两两个拆分 拆分到单个之后 再逐级排序合并 他的算法的空间复杂度为On 时间复杂度为nlog2n

#include <iostream>
using namespace std;
/**
 *功能:将两个有序的数组合并成一个整体有序的数组
 */
void mergeArr(int arr[], int low, int mid, int hight) {
	int* tempArr = new int[hight - low + 1];
	int i = low, j = mid + 1, k = 0;
	while (i <= mid && j <= hight) {
		if (arr[i] < arr[j]) {
			tempArr[k] = arr[i];
			i++;
		}
		else {
			tempArr[k] = arr[j];
			j++;
		}
		k++;
	}
	// 如果 arr[low] 到 arr[mid] 区间中的数组还没有比较完成 ,直接复制到tempArr 中
	while (i <= mid) {
		tempArr[k] = arr[i];
		i++;
		k++;
	}
	// 如果 arr[mid+1] 到 arr[hight] 区间中的数组还没有比较完成 ,直接复制到tempArr 中
	while (j <= hight) {
		tempArr[k] = arr[j];
		j++;
		k++;
	}
	// 比较完成之后 将原本的数组arr 下标 low-hight 对应的内容 进行改变
	i = low;
	for (int tempK = 0;((tempK < k)&&(i<=hight));tempK++) {
		arr[i] = tempArr[tempK];
		i++;
	}
	delete[] tempArr;
	tempArr = NULL;
	
}
/**
 *功能:拆分有序的序列两两排序-拆解结束的条件 子序列长度为1的时候
 */
void sortArr(int arr[], int low, int hight) {
	if (low < hight) {
		int mid = (hight + low) / 2;
		sortArr(arr,low,mid);// 递归拆解左边的序列
		sortArr(arr, mid + 1, hight);// 递归拆解左边的序列
		mergeArr(arr, low, mid, hight);// 将两个有序的子序列(arr[low至mid]、arr[mid+1至hight] 排序合并成一个新的有序列
	}
}

int main() {

	int arr[] = {5,4,6,3,1,2,8,7,10};
	cout << "before sort " << endl;
	for (int j = 0;j < 9;j++) {
		cout << arr[j] << "   ";
	}
	sortArr(arr,0,8);
	cout << endl << "after sort " << endl;
	for (int j = 0;j <9;j++) {
		cout << arr[j] << "   ";
	}
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

四、运行结果截图

在这里插入图片描述

如果有什么问题需要指正 欢迎在文章底下 友善 的留言 指正 一起进步一起成长。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/588933
推荐阅读
相关标签
  

闽ICP备14008679号