归并排序

算法竞赛 入门经典---刘汝佳  第八章    我就打一遍博客,再次熟悉原理。。。。。。。

归并排序

第一种高效的排序算法是归并排序。按照分治 三部法,对归并排序的介绍如下。

1.划分问题: 把序列分成元素个数尽量相等的两半。

2.递归求解: 把两半元素分别排序。

3.合并问题: 把两个有序表合并成一个。

书上的介绍就是这样,但如果是新手肯定不会懂于是我特意找了一张图帮助理解,

 

 百闻不如一见,排序的思路一看没有问题就会懂。

接下来是代码:
 

#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> ve;
int n;
ve nums;
void merge_sort(ve& nums, int start, int end) {
	if(end - start > 1) {                               //左闭  右开   **********例如:1 2 3   [1,2)    [2,3)
		int mid = start + (end-start)/2;                //向下取整
		merge_sort(nums, start, mid);                   //拆分
		merge_sort(nums, mid, end);			           // 拆分
		ve temp(n);                                    //创建临时的数组储存值
		int i = start, j = mid, k = start;            //后面要变化这些变量 所以  创建新的变量存储
		while(i < mid || j < end ) {
			if(j >= end || (i < mid && nums[i] < nums[j]))  temp[k++] = nums[i++];
			else temp[k++] = nums[j++];
		}
		for(int u = start; u < k; ++u) nums[u] = temp[u];     //注意是从 哪里开始赋值的 这里 很重要
	}
}
int main() {
	cin >> n;                 //输入你需要排序的个数
	int temp;              
	for(int i = 0; i < n; ++i) 	cin >> temp,nums.push_back(temp);  //getin n
	merge_sort(nums, 0, n);              //左闭  右开
	for(int i = 0; i < n; ++i)  cout << nums[i] << " ";
	return 0;
}

时间复杂度是 O(nlogn),证明我也不会,脑子理想一遍过程 就知道 它是小于 O(n^2)的。。。。

值得注意的是,边界条件要一直注意,利用左闭右开 , 还有就是 || 的用法, 但左式子成立时就不会考虑右边的式子。

利用这一点可以简化代码,while循环的赋值等价于下面代码:

        while (i < mid &&j < end) {                                //挑选两部分中最小的元素放入辅助数组中
        if (nums[i] < nums[j])
            temp[k++] = nums[i++];
        else
            temp[k++] = nums[j++];
    }
    while (i < mid)//如果还有剩余,直接放入到辅助数组中
        temp[k++] = nums[i++];
    while (j < end)
        temp[k++] = nums[j++];

巧用 || 确实可以 简化代码但是, 思维的理解却是在原来代码上基础的上改进的。。。各有各的好处。

 

以下是用迭代写的:(迭代难理解,但是写出来就很简单找错,下面是在第一个的代码上强行加上去的)

#include <iostream>
#include <vector>
using namespace std;
typedef vector<int> ve;
int n;
ve nums, nums1;
void merge_sort(ve& nums, int start, int end) {
	if(end - start > 1) {                               //左闭  右开   **********例如:1 2 3   [1,2)    [2,3)
		int mid = start + (end-start)/2;                //向下取整
		merge_sort(nums, start, mid);                   //拆分
		merge_sort(nums, mid, end);			           // 拆分
		ve temp(n);                                    //创建临时的数组储存值
		int i = start, j = mid, k = start;            //后面要变化这些变量 所以  创建新的变量存储
		while(i < mid || j < end ) {
			if(j >= end || (i < mid && nums[i] < nums[j]))  temp[k++] = nums[i++];
			else temp[k++] = nums[j++];
		}

//		while (i < mid &&j < end) {                                //挑选两部分中最小的元素放入辅助数组中
//		if (nums[i] < nums[j])
//			temp[k++] = nums[i++];
//		else
//			temp[k++] = nums[j++];
//	}
//	while (i < mid)//如果还有剩余,直接放入到辅助数组中
//		temp[k++] = nums[i++];
//	while (j < end)
//		temp[k++] = nums[j++];

		for(int u = start; u < k; ++u) nums[u] = temp[u];     //注意是从 哪里开始赋值的 这里 很重要
	}
}
void merge_sort1(ve& nums1) {  //利用迭代实现代码。
	for(int step = 2; step < n*2; step*=2 ) {
		for(int i = 0; i <= n; i += step) {
			int mid = i + step/2,start = i,	end = min(i + step, n);//这个end的边界条件要注意
			if(mid < n) {                 //如果中点在范围内,才执行下面的处理
				int s = start, e = mid, k = start;
				ve temp(n);
				while(s < mid || e < end ) {
					if(e >= end || (s < mid && nums1[s] < nums1[e]))  temp[k++] = nums1[s++];
					else temp[k++] = nums1[e++];
				}
				for(int u = start; u < k; ++u) nums1[u] = temp[u];     //注意是从 哪里开始赋值的 这里 很重要
//				cout << step << " " << start << ' ' <<mid << ' ' << end << endl;	for(int i = 0; i < n; ++i)  cout << nums1[i] << " ";
//					cout <<endl;
			}
		}
	}
}
int main() {
	cin >> n;                 //输入你需要排序的个数
	int temp;
	for(int i = 0; i < n; ++i) 	cin >> temp,nums.push_back(temp);  //getin n
	nums1 = nums;
	merge_sort(nums, 0, n);              //左闭  右开
	for(int i = 0; i < n; ++i)  cout << nums[i] << " ";
	cout << endl ;
	merge_sort1(nums1);
	for(int i = 0; i < n; ++i)  cout << nums1[i] << " ";
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值