排序——归并排序(分治法)

在写归并排序之前,首先谈一谈分治的思想,

所谓分治:就是将一个比较复杂的问题分解为若干个规模较小的但是类似原问题的子问题,(解决)递归地求解这些这些子问题,再合并这些子问题的解来求解原问题

可分为三步:

分解:将原问题分解为若干个规模较小的但是类似原问题的子问题

求解:递归地求解这些这些子问题,然而若子问题规模足够小,可直接求解

合并:合并这些子问题的解来求解原问题

接下来,终于可以写归并排序了

分解:将一个有N个数的数列分解为2个分别有n/2个数的2个子数列

求解:使用归并排序递归地分别排序两个子数列;

合并:将两个子数列合并并排好序

根据上面的思路,归并排序的思路如下

分解:N可能为奇数可能为偶数,要充分考虑到,mergesort函数如下

void mergeSort(int* A,int p,int r)
{
    if(p<r)
    {
    int q=(p+r)/2;
    mergeSort(A,p,q);
    mergeSort(A,q+1,r);
    merge(A,p,q,r);
    }

}

注意,要考虑到p=r(p为一个数组中将要排序的起始项下标,r为一个数组中将要排序的终止项下标),若p=r,则根本不需要排序

,接下来,就是负责合并两个有序数列(注意:这里是一个循环不变式,先假设两个子数列都以排好序,起始:只有一个数,已排好序,不变:合并排序函数merge保证他们排好序,终止:递归结束),这里有两种方法:哨兵法和非哨兵法

哨兵法:所谓哨兵就是在L数列和R数列尾部分别添加一个近乎无穷大的数防止在判断L[i]和[j]时越界

    int n1=q-p+1;
    int n2=r-q;

    int *L=(int*)malloc((n1+1)*sizeof(int));
    int *R=(int*)malloc((n2+1)*sizeof(int));

    int t,tmp1=0,tmp2=0;
    for(t=p;t<=q;t++) {
        *(L+tmp1)=*(A+t);
        tmp1++;
    }
    for(t=q+1;t<=r;t++) {
        *(R+tmp2)=*(A+t);
        tmp2++;
    }
    *(L+n1)=ShaoBing;
    *(R+n2)=ShaoBing;

    int i=0,j=0;
    int k;

/*
  依次从两个数字中取元素,将小的放入原数组中
*/
    for(k=p;k<=r;k++) {
        if(*(L+i)<=*(R+j)) {
            *(A+k)=*(L+i);
            i++;
        }
        else {
            *(A+k)=*(R+j);
            j++;
        }
    }
    free(L);
    free(R);

非哨兵法:没有哨兵防止越界,就只能分    int n1=q-p+1    int n2=r-q    int *L=(int*)malloc((n1+1)*sizeof(int));    int *R=(int*)malloc((n2+1)*sizeof(int));

int t,tmp1=0,tmp2=0;
    for(t=p;t<=q;t++) {
        *(L+tmp1)=*(A+t);
        tmp1++;
    }
    for(t=q+1;t<=r;t++) {
        *(R+tmp2)=*(A+t);
        tmp2++;
    }
    *(L+n1)=ShaoBing;
    *(R+n2)=ShaoBing;

    int i=0,j=0;
    int k;

/*
  依次从两个数字中取元素,将小的放入原数组中
*/
    for(k=p;k<=r;k++) {     if(i==n1)      {        while(j<n2)        {          *(A+k)=*(R+j);            j++;            k++;        }        break;      }    if(j==n2)      {        while(i<n1)        {          *(A+k)=*(L+i);          i++;          k++;        }        break;      }      if(*(L+i)<=*(R+j)) {
            *(A+k)=*(L+i);
            i++;
        }
        else {
            *(A+k)=*(R+j);
            j++;
        }
    }
    free(L);
    free(R);

以上是我的思考路程,附上一篇博文,归并写得比较好,参考

时间: 2024-10-14 04:51:22

排序——归并排序(分治法)的相关文章

合并排序(分治法)

使用分治法进行合并排序,问题描述参见:https://www.cnblogs.com/jingmoxukong/p/4308823.html 算法核心: //merge_sort.h #ifndef MERGE_SORT_H #define MERGE_SORT_H template <class Type> void MergeSort(Type a[], int n); #include "merge_sort.template" #endif //merge_sort

数据结构之分治法(最短距离)-(十一)

package com.lip.datastructure; /** * @author lip * 分治法,所谓分治当然是分而治之,化整为零. * 分治法分为两部分,1.分(Divide)2.治(Conquer) * 在排序算法中我们用到的二分排序就是分治法最经典的一个例子 * 传统的分治法要运行两次及其以上的递归算法,一般用分治法解决问题的时间复杂度是O(N*lgN) */ public class DivideAndConquer { /*求平面上两个点的最短距离 * 方法一:就是两个fo

分治法排序之归并排序

使用分治法的两路合并排序算法: 将待排序的元素序列一分为二,得到长度基本相等的两个子序列,分别排序. 如果子序列较长,还可继续细分,直到子序列的长度不超过1为止. 当分解所得的子序列已排列有序时,将两个有序子序列合并成一个有序子序列,得到原问题的解. 合并方法: 比较两序列中的最小值,输出其中较小者,然后重复此过程,直到其中一个队列为空时, 如果另一个队列还有元素没有输出,则将剩余元素依次输出. #include<stdio.h>#define N 100int merge(int *a, i

算法实验:分治法合并排序(C++)

这篇文章分两部分来写,第一部分写代码的实现过程,第二部分把实验报告从头到尾呈现出来. 我习惯调试使用的编译器是DEV C++,不是vs系列的,可能头文件上有点区别.但是下面的报告是我放到vs里面测试过的,可以直接用,不影响. 第一部分:(解析) 题目:随机产生一个整型数组,然后用合并排序将该数组做升序排列,要求输出排序前和排序后的数组. 题目分析: 需要随机产生一个整数数组: 采用的算法是合并排序,也就是用归并排序: 输出排序后的数组. 随机产生一个整数数组:这个问题首先想到的是用rand()函

算法设计《分治法》归并排序(三)实例分析之逆序对数

问题定义: 假设A[1...n]是一个有n个不同数的数组.若i<j且A[i]>A[j]则称(A[i], A[j])为数组A的一个逆序对. 例如数组<2, 3, 8, 6, 1>有(2, 1),(3, 1),(8, 6),(8, 1)和(6,1)5个逆序对. 对于这个问题,直观上进行求解的话,使用暴力求解的方式的话,对于每个数num,都遍历数组中num后的所有数的话,则时间复杂度为O(n^2). 实现代码如下: 另一种方式,便是使用分治法,首先将整个数组分成两部分,然后,分别求解两个

算法导论第2章 分治法与归并排序, 二分查找法

分治策略:将原问题划分成n个规模较小而结构与原问题相似的子问题,然后递归地解决这些子问题,最后再合并其结果,就可以得到原问题的解. 它需要三个步骤: 分解:将原问题分解成一系列的子问题. 解决:递归地解决各个子问题.若子问题足够小,则直接求解. 合并:将子问题的结果合并成原问题的解. 通过分治策略和分治步骤,可以简单地默出归并算法. 分解:将n个元素分成各自包含n/2个元素的子序列 解决:用归并排序法递归地对两个子序列进行排序. 合并:合并两个以排序的子序列,得到排序结果: void merge

归并排序(分治法)

横向想了一下这几个经典的排序算法,个人感觉快排应该是速度最快了,首先快排在空间复杂度的角度应该开销比归并要小很多,因为归并需要申请新的临时空间,时间复杂度上虽说都是N*log(n).但是同一个数量级上归并有很多的数组复制操作,感觉如果数据很大的话应该比快排所消耗的时间多很多(但是都是在一个数量级上,比如100 和900的区别).本来想等考完试有时间去做一下试验,但是今天发现有博主已经做了,嘻嘻,那我就直接转载过来了.(这个博主安利下,他的文章深入浅出,对新手很友好) 贴试验之前,先整理一下归并排

python实现分治法排序

# -*- coding: utf-8 -*- """ Created on Wed May 14 16:14:50 2014 @author: lifeix """ def merge(a, start, mid, end): if start == end: return a if mid == 0: return a temp1 = a[start:mid] m1 = len(temp1)/2 print temp1,'----',m1 n

分治法-合并排序和快速排序

分治法是按照以下方案工作的: 将问题的实例划分为同一个问题的几个较小的实例,最好拥有同样的规模 对这些较小的实例求解(一般使用递归方法,但在问题规模足够小的时候,有时会利用另一种算法以提高效率) 如果必要的话,合并较小问题的解,以得到原始问题的解 分治法的流程: 4.1 合并排序 合并排序是成功应用分治技术的一个完美例子(书上说的). 对于一个需要排序的数组,合并排序把它一分为二,并对每个子数组递归排序,然后把这两个排好序的子数组合并为一个有序数组. 代码实现: /** * 合并排序 * @au

分治法 ----归并排序

分治法的思想就是把一个难以解决的大问题分解成很多个小规模的问题--分而治之,说实话我不明白和dp的区别 /* Name: Copyright: Author: 流照君 Date: 2019/9/13 11:03:29 Description: */ #include <iostream> #include<string> #include <algorithm> #include <vector> #define inf 10010 using namesp