• 算法:归并排序


    归并排序是一种非常经典的分治算法,也是非常精美的算法。学习归并排序,对于理解分治法思想、提高算法思维能力十分有帮助。

    例题

    洛谷1177 排序

    题目描述
    将读入的 N 个数从小到大排序后输出。

    输入格式
    第 1 行为一个正整数 N。
    第 2 行包含 N 个空格隔开的正整数 a[i],为你需要进行排序的数,数据保证了a[i]不超过10^9。

    输出格式
    将给定的 N个数从小到大输出,数之间用空格隔开。

    输入输出样例
    输入

    5
    4 2 4 5 1
    

    输出

    1 2 4 4 5
    

    说明提示
    对于20% 的数据,有 N <= 10^3。
    对于100% 的数据,有 N <=10^5 。

    归并排序

    分治算法最重要的三个步骤:

    1. 分解:如果我们要去把整个序列排序,可以去把序列拆成前后两部分(这里取序列中间的数a[mid]为分界点)。
    2. 解决:分别用分治思想再去将拆成的这两个部分进行排序,这里用递归来做。(具体些就是再去把这两个部分拆成4个部分,之后再去不停地拆)。
    3. 合并:每次把前后两已排序好的部分进行合并,合并方法就是新建一个数组ans,之后因为前后两部分都是排好序的,也就都具有单调性,每次把前后两个序列的首元素较小的先放到ans中,之后把这个首元素在原序列中删去,直到两序列都为空。

    这里再把合并的思路说具体一些:设t1 = l,t2 = mid + 1分别表示,前部分当前剩余的元素有a[t1] ~ a[mid],后部分当前剩余的元素有a[t2] ~ a[r]。每次如果a[t1] < a[t2],就在ans数组后面加一个a[t1],之后t1++;否则就在ans数组后面加一个a[t2],之后t2++。

    还有递归的边界条件,就是当序列为空或只有一个元素时返回,即l >= r时return。

    举个例子,便于理解。
    初始状态:6,202,100,301,38,8,1
    第一次归并后:{6,202},{100,301},{8,38},{1}
    第二次归并后:{6,100,202,301},{1,8,38}
    第三次归并后:{1,6,8,38,100,202,301}

    最后算一下这个算法的时间复杂度:每次拆分是log2(n)次,合并的话n次就行,所以平均时间复杂度是O(n * log2(n))级别。

    代码

    # include <cstdio>
    # include <cmath>
    # include <cstring>
    # include <algorithm>
    
    using namespace std;
    
    const int N_MAX = 100000;
    
    int n;
    int a[N_MAX + 10];
    
    void mergeArray(int l, int mid, int r)
    {
    	int ans[N_MAX + 10], len = 0;
    	int t1 = l, t2 = mid + 1;
    	while(t1 <= mid && t2 <= r){
    		if(a[t1] < a[t2]) ans[++len] = a[t1++];
    		else ans[++len] = a[t2++];
    	}
    	while(t1 <= mid) ans[++len] = a[t1++];
    	while(t2 <= r) ans[++len] = a[t2++];
    	for (int i = l; i <= r; i++)
    		a[i] = ans[i - l + 1];
    }
    
    void mergeSort(int l, int r)
    {
    	if(l >= r) return;
    	int mid = (l + r) / 2;
    	mergeSort(l, mid);
    	mergeSort(mid + 1, r);
    	mergeArray(l, mid, r);
    }
    
    int main()
    {
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++)
    		scanf("%d", &a[i]);
    	mergeSort(1, n);
    	for (int i = 1; i <= n; i++)
    		printf("%d ", a[i]);
    	printf("
    ");
    	return 0;
    }
    
  • 相关阅读:
    float:left的妙用
    ajax实现注册并选择头像后上传
    Javascript中target事件属性,事件的目标节点的获取。
    Bootstrap解决页面缩小变形的办法
    UICollectionView布局功能
    UITaleView的基础使用及数据展示操作
    scrollView实现基础中心点缩放及与UIPageControl结合使用
    自定义UITableViewCell
    属性传值,协议传值,block传值,单例传值四种界面传值方式
    操作符:一元操作符、布尔值操作符(逻辑操作符)、加性操作符、乘性操作符、关系操作符、相等操作符、条件操作符以及赋值操作符
  • 原文地址:https://www.cnblogs.com/000zwx000/p/12330618.html
Copyright © 2020-2023  润新知