c++ 归并排序

归并排序算法时间复杂度较为稳定,一般为nlogn,而快速排序受源数组排序影响较大,今天来学习归并排序。

一.归并排序代码

首先上代码:可以直接运行

#include<bits/stdc++.h>
using namespace std;

void insertsort(vector<int>&nums, int left,int mid, int right)
{
	if (nums[mid] <= nums[mid + 1])
		return;
	for (int i = left+1; i <= right; ++i)
	{
		int idx = i;
		while (idx > left && nums[idx] < nums[idx - 1])
		{
			swap(nums[idx], nums[idx-1]);
			--idx;
		}			
	}
}

vector<int>temp;
void merge(vector<int>&nums,int left,int mid,int right)
{
	if (nums[mid] <= nums[mid + 1])
		return;

	for (int i = left; i <= right; ++i)
		temp[i] = nums[i];
	int x = left, y = mid + 1;
	for (int i = left; i <= right; ++i)
	{
		if (y > right|| (y<=right&&x<=mid&&temp[x] <= temp[y]))
		{
			nums[i] = temp[x];
			++x;
		}			
		else if (x>mid||(x<=mid&&temp[x]>temp[y]))//条件可省略
		{
			nums[i] = temp[y];
			++y;
		}			
	}
}


void mergesort(vector<int>&nums,int left,int right)
{
	if (left >=right) return;
	int mid = left + (right - left)/2;
	mergesort(nums, left, mid);
	mergesort(nums, mid + 1, right);
	if (mid - left + 1 <= 10)
		insertsort(nums, left, mid, right);
	else
		merge(nums, left, mid, right);
}


int main()
{
	vector<int>nums = { 2,1,4,6,5,88,99,0,999};
	int n = nums.size();
	temp.resize(n);
	mergesort(nums,0,n-1);
	for (auto &num : nums)
		cout << num << endl;
	return 0;
}

二.代码详解

1.主函数

主函数较为简单,就是定义数组,然后调用mergesort函数,最后打印输出。

值得注意的是在主函数中我们将一个temp数组定义了大小,这个数组是辅助数组,在详细的有序合并的操作中用得到,因为我们需要好多次的合并,每次合并后的数组都不一样。

2.mergesort函数

这个函数就是一个递归函数,不断地去分割,直到分割到最后只有一个元素时,它会退出分割操作,然后这个元素会和分割出的另一半元素进行合并操作,合并完成跳到上一级继续合并。

3.merge合并函数

在合并函数中,首先如果左右两个已经是有序的,则不需要合并,直接返回。

然后我们将要合并的left到right之间的元素拷贝到temp辅助数组中,

因为原来左右两边就是有序的,所以我们只关注左右两边的起始索引,将较小的那个放进nums[i]中,

特别要注意的是元素过界问题,因为只是归并操作,索引并不会突破数组上限,从而造成结果不正确而很难发现出问题。

如果说y右侧索引超出了限定right,我们将temp[x]赋值给nums[i],此时x不会出上限。

或者说y没出索引,x也没出索引,那么当temp[x]<temp[y]时,我们也将temp[x]赋值给nums[i].

其余情况均是temp[y]赋值给nums[i]。

4.插入排序insertsort 

当right-left特别小的时候,我们可以直接使用插入排序,想象一下我们只有两个元素[2,1],

插入排序只需要swap两个值即可,而不需要赋值给赋值数组。

插入排序的思想是前面的数组元素是有序的,那么我遍历到第idx个元素时,我要把它插入到前面的合适位置,特别地如果这个值比较大,那么它不用动,

如果它比较小,那么让他和idx-1的数进行不断交换,直到遇到合适的位置。 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C语言实现归并排序算法的代码和注释: ```c #include <stdio.h> /* 归并排序函数 */ void merge_sort(int arr[], int left, int right); /* 合并两个有序数组 */ void merge(int arr[], int left, int mid, int right); /* 主函数 */ int main() { int arr[] = {3, 5, 1, 2, 6, 4}; int len = sizeof(arr) / sizeof(arr[0]); // 数组长度 merge_sort(arr, 0, len - 1); // 调用归并排序 for (int i = 0; i < len; i++) { printf("%d ", arr[i]); // 输出排序后的数组 } return 0; } void merge_sort(int arr[], int left, int right) { if (left >= right) { return; // 当数组只有一个元素时,直接返回 } int mid = (left + right) / 2; // 求中间位置 merge_sort(arr, left, mid); // 对左半部分进行递归排序 merge_sort(arr, mid + 1, right); // 对右半部分进行递归排序 merge(arr, left, mid, right); // 合并左右两个有序数组 } void merge(int arr[], int left, int mid, int right) { int len = right - left + 1; int *tmp = (int*)malloc(len * sizeof(int)); // 申请临时数组 int i = left; // 左半部分数组起始位置 int j = mid + 1; // 右半部分数组起始位置 int k = 0; // 临时数组起始位置 while (i <= mid && j <= right) { if (arr[i] <= arr[j]) { tmp[k++] = arr[i++]; // 将左半部分数组元素放入临时数组中 } else { tmp[k++] = arr[j++]; // 将右半部分数组元素放入临时数组中 } } while (i <= mid) { tmp[k++] = arr[i++]; // 将剩余的左半部分数组元素放入临时数组中 } while (j <= right) { tmp[k++] = arr[j++]; // 将剩余的右半部分数组元素放入临时数组中 } for (int m = 0; m < len; m++) { arr[left + m] = tmp[m]; // 将临时数组中的元素复制回原数组中 } free(tmp); // 释放临时数组的内存空间 } ``` 代码注释: 1. `merge_sort`函数:归并排序函数,用于将数组的左半部分和右半部分进行递归排序,并将两个有序数组合并成一个有序数组。参数`arr`为要排序的数组,参数`left`为数组左边界,参数`right`为数组右边界。 2. `merge`函数:合并两个有序数组,用于将数组的左半部分和右半部分合并成一个有序数组。参数`arr`为原始数组,参数`left`为左半部分数组的起始位置,参数`mid`为左半部分数组的终止位置,参数`right`为右半部分数组的终止位置。 3. `main`函数:主函数,用于测试归并排序的效果。 4. 在`merge`函数中,首先计算出临时数组的长度,然后申请临时数组的内存空间。接着,使用双指针法将左半部分数组和右半部分数组进行合并,将合并后的有序数组存放在临时数组中。最后,将临时数组中的元素复制回原数组中,并释放临时数组的内存空间。 5. 在`merge_sort`函数中,首先判断数组是否只有一个元素,如果是,则直接返回。否则,计算出数组的中间位置`mid`,然后对数组的左半部分和右半部分进行递归排序,并将排序后的两个有序数组合并成一个有序数组。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值