归并排序—C++实现

相比于快速排序,归并排序就十分稳定,无论是最好还是最差的情况,它的时间复杂度都为O(nlogn)。归并排序同样利用了递归的思想,它的思想是把一个问题分解成多个小问题,然后一个一个解决再合并起来,这种思想对我们的工作生活也同样很有帮助,废话不多说,下面来实际看看归并排序。

归并排序会将数组对半分开直到不可分割为止。
在这里插入图片描述
然后每一个子块会排序后向上合并。

在这里插入图片描述
与快速排序不同的是,归并排序会递归到无法分割才会开始排序,然后不停合并。
下面我们来看看C++如何实现归并排序

归并排序代码

#include<iostream>
//使用动态数组存储数据
#include<vector>
using namespace std;
template<typename T>
//输出运算符重载模板,方便输出vector数组
template<typename T>
ostream& operator<<(ostream& os, vector<T> v)
{
	os << "[";
	for (auto i: v )
	{
		os << i << ",";
	}
	os << "\b]" << endl;
	return os;
}

//合并,默认Ascending为true,升序合并,Ascending为false时降序合并
//vec	要进行归并的数组
//left	左边的位置
//mid	中间的位置
//right	右边的位置
template<typename T>
void merge(vector<T> &v, int left,int mid, int right,bool Ascending = true)
{
	//拷贝一份数组
	vector<T> temp(v.begin() + left, v.begin() + right + 1);
	//指向左边块的元素下标
	int lt = left;
	//指向右边块的元素下标
	int rt = mid+1;
	//默认为升序排序
	if (Ascending)
	{
		//一次合并
		for (int i = left; i <= right; i++)
		{
			if (lt > mid)//左边的位置到底了,将右边的归并上去
			{
				v[i] = temp[rt - left];
				rt++;
			}
			else if (rt > right)//右边的位置到底了,将左边的归并上去
			{
				v[i] = temp[lt - left];
				lt++;
			}
			else if (temp[rt - left] > temp[lt - left])//左边和右边的索引元素进行比较
			{
				//左边的数据小,左边的归并上去
				v[i] = temp[lt - left];
				lt++;
			}
			else
			{
				//右边数据小,右边的归并上去
				v[i] = temp[rt - left];
				rt++;
			}
		}
	}
	//降序排序
	else
	{
		for (int i = left; i <= right; i++)
		{
			if (lt > mid)
			{
				v[i] = temp[rt - left];
				rt++;
			}
			else if (rt > right)
			{
				v[i] = temp[lt - left];
				lt++;
			}
			else if (temp[rt - left] < temp[lt - left])
			{
				v[i] = temp[lt - left];
				lt++;
			}
			else
			{
				v[i] = temp[rt - left];
				rt++;
			}
		}
	}
}

//归并排序,先分割到不可分割,再排序
template<typename T>
void merge_sort(vector<T> &v, int left, int right, bool Ascending = true)
{
	if (left>=right)
	{
		return;
	}
	int mid = (left + right) / 2; //准备分解的中间位置
	merge_sort(v, left, mid, Ascending);//继续分割左边的数据
	merge_sort(v, mid + 1, right, Ascending);//继续分割右边的数据
	merge(v, left, mid, right,Ascending);//合并左右的数据(执行到这时左右已经有序)
}
//随机给所有元素赋值
template<typename T>
void random(vector<T>& v)
{
	srand((unsigned int)time(nullptr));
	for (auto& e : v)	
	{
		e = (rand() + rand()) % (v.size());
	}
}

//主函数测试
int main(void)
{
	vector<int> vec(100);
	random(vec);
	//如果需要降序排序,只需要再最后传入false
	//fast_sort(vec, 0, vec.size() - 1, false);
	merge_sort(vec, 0, vec.size() - 1);
	cout << vec;
	return 0;
}

运行结果如下:
在这里插入图片描述
虽然归并排序比快速排序的效率更加稳定,但是它是牺牲了空间的,它的空间复杂度为O(n)。在使用归并排序的时候一定要确保内存空间的大小足够。


百闻不如一见,下面博主通过将大小为一万的随机数组进行排序,通过比较冒泡排序,归并排序,快速排序所用的时间来直观地感受三者的效率。
下面给出冒泡排序和快速排序的函数,由于需要用到时间,请导入头文件#include <ctime>
冒泡排序

template<typename T>
void bubbling_sort(vector<T> &v)
{
	int length = v.size();
	for (unsigned int i = 0; i < v.size(); i++)
	{
		length--;
		for (int j = 0; j < length; j++)
		{
			if (v[j]>v[j+1])
			{
				swap(v[j], v[j + 1]);
			}
		}
	

快速排序

template<typename T>
void fast_sort(vector<T> &v, int left, int right,bool Ascending=true)
{
	//当左边的下标大于等于右边即视为不可分割,递归结束
	if (left>=right)
	{
		return;
	}

	int pt = left+1;
	//基准值
	T val = v[left];
	//默认为升序排序
	if (Ascending)
	{
		//一次快速排序
		for (int i = left + 1; i <= right; i++)
		{
			if (val > v[i])
			{
				swap(v[i], v[pt++]);
			}
		}
	}
	//降序排序
	else
	{
		for (int i = left + 1; i <= right; i++)
		{
			if (val < v[i])
			{
				swap(v[i], v[pt++]);
			}
		}
	}
	swap(v[left], v[--pt]);
	//将左边进行快速排序
	fast_sort(v, left, pt-1,Ascending);
	//将右边进行快速排序
	fast_sort(v, pt+1, right,Ascending);
}

主函数

int main(void)
{
	vector<int> vec(10000);
	random(vec);
	vector<int> vec1(vec);
	vector<int> vec2(vec);
	cout << "归并排序:" << endl;
	clock_t start = clock();
	merge_sort(vec, 0, vec.size() - 1);
	clock_t end = clock();
	cout << "排序的数据量:" << vec.size() << endl;
	cout << "排序用到的时间:" << (float)(end - start) / 1000 << "s" << endl;
	cout << "============" << endl;
	cout << "快速排序:" << endl;
	clock_t start1 = clock();
	fast_sort(vec1, 0, vec1.size() - 1);
	clock_t end1 = clock();
	cout << "排序的数据量:" << vec.size() << endl;
	cout << "排序用到的时间:" << (float)(end1 - start1) / 1000 << "s" << endl;
	cout << "============" << endl;
	cout << "冒泡排序:" << endl;
	clock_t start2 = clock();
	bubbling_sort(vec2);
	clock_t end2 = clock();
	cout << "排序的数据量:" << vec2.size() << endl;
	cout << "排序用到的时间:" << (float)(end2 - start2) / 1000 << "s" << endl;
	return 0;
}

运行结果如下:
在这里插入图片描述
可以看到归并排序和快速排序的效率都是很不错的,而冒泡排序的效率可就太低了。虽然看起来快速排序的效率最高,但是之前也说过了,快速排序在极端情况下可能效率与冒泡排序相当。

今天的分享就到这里了,希望大家能够有所收获。

猜你喜欢

转载自blog.csdn.net/weixin_42494845/article/details/106124314