【归并排序】

  1. 冒泡排序
  2. 选择排序
  3. 快速排序
  4. 插入排序
  5. 希尔排序
  6. 堆排序
  7. 计数排序
  8. 桶排序
  9. 基数排序

1. 算法思想

  • 将一个大的无序数组有序化,可以把大的数组分成两个,然后对这两个数组分别进行排序,之后在把这两个数组合并成一个有序的数组,由于两个小的数组都是有序的,所以合并时很快
  • 通过 递归 的方式将大的数组一直分割,直到数组的大小为 1,此时只有一个元素,那么该数组就是有序的了,之后把两个数组大小为1的合并成一个数组大小为2的,再把两个数组大小为2的合并成大小为4的…直到全部的小数组合并起来。
  • 归并排序是建立在归并操作上的一种有效的排序算法,该算法是 分治法 的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

2. 算法步骤

  1. 把长度为n的输入序列分成两个长度为n/2的子序列;
  2. 对这两个子序列分别采用归并排序;
  3. 将两个排序好的子序列合并成一个最终的排序序列。

3. 代码实现(C++)

3.1 vector 类型的递归

#include<iostream>
#include<vector>
using namespace std;

void printVector(vector<int>& nums)
{
	for (auto num : nums)
	{
		cout << num << " ";
	}
	cout << endl;
}

void mergeSortCore(vector<int>& data, vector<int>& dataTemp, int low, int high)
{
	if (low >= high)
	{
		return;
	}
	int len = high - low, mid = low + len / 2;
	int start1 = low, end1 = mid, start2 = mid + 1, end2 = high;
	mergeSortCore(data, dataTemp, start1, end1);
	mergeSortCore(data, dataTemp, start2, end2);
	int index = low;
	while (start1 <= end1 && start2 <= end2)
	{
		dataTemp[index++] = data[start1] < data[start2] ? data[start1++] : data[start2++];
	}
	while (start1 <= end1)
	{
		dataTemp[index++] = data[start1++];
	}
	while (start2 <= end2)
	{
		dataTemp[index++] = data[start2++];
	}

	for (index = low; index <= high; ++index)
	{
		data[index] = dataTemp[index];
	}
}

void mergeSort(vector<int>& data)
{
	int len = data.size();
	vector<int> dataTemp(len, 0);
	mergeSortCore(data, dataTemp, 0, len - 1);
}

int main()
{
	vector<int> nums = { 8,7,1,4,2,3,6,9,5 };

	cout << "排序前:" << endl;
	printVector(nums);

	mergeSort(nums);

	cout << "排序后:" << endl;
	printVector(nums);

	//system("pause"); //按任意键继续
	return 0;
}

3.2 vector 类型的迭代

#include<iostream>
#include<vector>
using namespace std;

void printVector(vector<int>& nums)
{
	for (auto num : nums)
	{
		cout << num << " ";
	}
	cout << endl;
}

void mergeSort(vector<int>& data)
{
	int len = data.size();
	vector<int> dataTemp(len, 0);
	for (int seg = 1; seg < len; seg += seg)
	{
		for (int start = 0; start < len; start += seg + seg)
		{
			int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
			int index = low, start1 = low, end1 = mid, start2 = mid, end2 = high;
			while (start1 < end1 && start2 < end2)
			{
				dataTemp[index++] = data[start1] < data[start2] ? data[start1++] : data[start2++];
			}
			while (start1 < end1)
			{
				dataTemp[index++] = data[start1++];
			}
			while (start2 < end2)
			{
				dataTemp[index++] = data[start2++];
			}
		}
		swap(data, dataTemp);
	}
}

int main()
{
	vector<int> nums = { 8,7,1,4,2,3,6,-3,5 };

	cout << "排序前:" << endl;
	printVector(nums);

	mergeSort(nums);
	
	cout << "排序后:" << endl;
	printVector(nums);

	//system("pause"); //按任意键继续
	return 0;
}

4. 总结

平均时间复杂度: O(n * log n)
最好情况: O(n * log n)
最坏情况:O(n * log n)
排序方式:非原地排序
稳定性:稳定
空间复杂度: O(n)

5. 补充知识

  • 稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 仍然在 b 的前面,则为稳定排序;
  • 非稳定排序:如果 a 原本在 b 的前面,且 a == b,排序之后 a 可能不在 b 的前面,则为非稳定排序。
  • 原地排序:原地排序就是指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序;
  • 非原地排序:需要利用额外的数组来辅助排序。
  • 时间复杂度:一个算法执行所消耗的时间(次数,因为同一程序在不同系统的执行时间可能不同);
  • 空间复杂度:运行完一个算法所需的内存大小。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值