排序算法:归并排序

归并排序

1. 将若干有序序列逐步归并为一个有序序列。
2. 二路归并:最简单,将若干有序序列两两归并,直至形成一个有序序列。
3. 采用的分治法。
4. 二路归并非递归思路:
    1. 将序列分成n个序列,每个序列一个元素,这样可以任务每个序列都是有序序列。
    2. 逐一合并两个相邻的序列,使得每个序列长度为2.
    3. 重复步骤2,直到序列的长度为n。
    4. 子序列合并过程中有三种情况
        1. 子序列数目为偶数且子序列长度相等。
        2. 子序列数目为偶数且最后一个子序列长度小于其他子序列。
        3. 子序列数目为奇数(最后剩下一个子序列)。
5.比较占内存、效率高、稳定的排序算法。

复杂度

1. 一趟归并排序:O(n)。
2. 整个归并排序,需要【log2n】取整趟,例如:8个数三趟。
3. 所以总的视觉代价是O(nlogn),最好、最坏、平均的时间性能。
4. 空间复杂度:非递归时候只需要O(n),小于递归时候占的内存,实际使用中推荐使用非递归方法。
5. 排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。

图示

代码实现

非递归方法

void Merge(int r[ ], int r1[ ], int s, int m, int t)
{
/*
    一次归并算法
    s:start m:middle t:tail
        r数组分为s——m,和m+1——t,两个部分。
        r1为归并好的数组。*/

    int i=s;
    int j=m+1;
    int  k=s;
    while (i<=m && j<=t)
    {
        if (r[i]<=r[j])
        {
            r1[k++]=r[i++];   //取r[i]和r[j]中较小者放入r1[k]
        }
        else
        {
            r1[k++]=r[j++];
        }
    }
    if (i<=m) while (i<=m)      //若第一个子序列没处理完,则进行收尾处理
    {
        r1[k]=r[i];
        i++;
        k++;
    }
    else  while (j<=t)       //若第二个子序列没处理完,则进行收尾处理
    {
        r1[k]=r[j];
        k++;
        j++;
    }
}
void MergePass(int r[ ], int r1[ ], int n, int h)
{
    //根据步长将相邻的两个子序列合并
    int i=1;
    //待归并记录至少有两个长度为h的子序列,之所以n+1,是因为我们从r[1]开始

    while(i<=(n-2*h+1))
    {
        //若每个子序列相等且是偶数个,则一直走这个循环1 3 …… n-2*h+1 n+1(不成立跳出循环)
        //将相邻的有序序列合并成一个有序序列
        Merge(r, r1, i, i+h-1, i+2*h-1);
        i = i + 2*h;
    }
    //待归并序列中有一个长度小于h,此时分为两段i——i+h-1,i+h——n,可推得i>(n-2*h+1)
    if (i<n-h+1)
    {   //当最后一个子序列长度小于其他子序列,且子序列数目为偶数
        //n+1-2h<i<n+1-h
        Merge(r, r1, i, i+h-1, n);
    }
    else
    {
        //待归并序列中只剩一个子序列,子序列数目为奇数,剩下的孤零零的一个子序列(长度<=h)
        for (int k=i; k<=n; k++)
        {
            r1[k]=r[k];
        }
    }
 }

void MergeSort1(int r[ ], int r1[ ], int n )
{
    cout<<"MergeSort:"<<endl;
    int h=1;//初始序列长度为1,当序列长度达到n时候,意味着排序完成,此时h>=n
    while (h<n)
    {
        int i ;
        MergePass(r, r1, n, h);
        cout<<"步长h:"<<h<<endl;
        for (i = 1;i<10;i++)
        {
            cout<<r1[i]<<" ";
        }
        cout<<endl;

        h=2*h;//每次序列合并之后,第一个单个序列长度为2h

        int *p = r;
        r = r1;
        r1 = p;
    }
}

递归方法

void Merge(int r[ ], int r1[ ], int s, int m, int t)
{
/*
    一次归并算法
    s:start m:middle t:tail
        r数组分为s——m,和m+1——t,两个部分。
        r1为归并好的数组。*/

    int i=s;
    int j=m+1;
    int  k=s;
    while (i<=m && j<=t)
    {
        if (r[i]<=r[j])
        {
            r1[k++]=r[i++];   //取r[i]和r[j]中较小者放入r1[k]
        }
        else
        {
            r1[k++]=r[j++];
        }
    }
    if (i<=m) while (i<=m)      //若第一个子序列没处理完,则进行收尾处理
    {
        r1[k]=r[i];
        i++;
        k++;
    }
    else  while (j<=t)       //若第二个子序列没处理完,则进行收尾处理
    {
        r1[k]=r[j];
        k++;
        j++;
    }
}
void MergeSort2(int r[ ], int r1[ ], int s, int t)
{
    int m;
    if (s==t)
    {
        r1[s]=r[s];
    }
    else
    {
        m=(s+t)/2;
        MergeSort2(r, r1, s, m);    //归并排序前半个子序列
        MergeSort2(r, r1, m+1, t);   //归并排序后半个子序列
        Merge(r1, r, s, m, t);      //将两个已排序的子序列归并

    }
    }

注意:代码中的排序都是从r[1]开始的。

时间: 2024-10-04 16:35:13

排序算法:归并排序的相关文章

排序算法——归并排序

归并排序是分治法的典型举例. 分治法的思想是,将原有问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 分治模式在每层递归时都有三个步骤: 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例. 解决这些子问题,递归地求解各子问题.然而,若子问题的规模足够小,则直接求解. 合并这些子问题的解成原问题的解. 归并排序算法完全遵循分治模式.直观上其操作如下: 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列. 解决:使用

经典排序算法 - 归并排序Merge sort

经典排序算法 - 归并排序Merge sort 原理,把原始数组分成若干子数组,对每个子数组进行排序, 继续把子数组与子数组合并,合并后仍然有序,直到所有合并完,形成有序的数组 举例 无序数组[6 2 4 1 5 9] 先看一下每一个步骤下的状态,完了再看合并细节 第一步 [6 2 4 1 5 9]原始状态 第二步 [2 6] [1 4] [5 9]两两合并排序,排序细节后边介绍 第三步 [1 2 4 6] [5 9]继续两组两组合并 第四步 [1 2 4 5 6 9]合并完成,排序完成 输出结

三种排序算法(归并排序、快速排序,堆排序)

归并排序:建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. 归并排序算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取. 工作原理: 1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后

经典排序算法---归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并 代码: void mergearray(struct SQ_LIST *v, int first, int mid, int last, int temp[]) { int i = first, j = mid + 1

js 实现排序算法 -- 归并排序(Merge Sort)

原文: 十大经典排序算法(动图演示) 归并排序 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为2-路归并. 算法描述 把长度为n的输入序列分成两个长度为n/2的子序列: 对这两个子序列分别采用归并排序: 将两个排序好的子序列合并成一个最终的排序序列. 动图演示 代码实现 function merg

(转)排序算法——归并排序与递归

基本思想 分析归并排序之前,我们先来了解一下分治算法. 分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同.求出子问题的解,就可得到原问题的解. 分治算法的一般步骤: (1)分解,将要解决的问题划分成若干规模较小的同类问题: (2)求解,当子问题划分得足够小时,用较简单的方法解决: (3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解. 归并排序是分治算法的典型应用. 归并排序先将一个无序的N长数组切成N个有序子序列(只有一个数据的

排序算法--归并排序(merge)

归并排序是利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列,归并排序包括两个步骤,分别为: 1)划分子表  2)合并半子表 时间复杂度是Θ(nlgn),优于插入排序算法. 算法描述    1) 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列    2) 设定两个指针,最初位置分别为两个已经排序序列的起始位置    3) 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到

Java排序算法——归并排序

基本思想归并排序利用分治法思想,先将一个序列分成一个个子序列,然后对子序列进行排序,再把有序子序列合并为整体有序序列. 两路归并排序算法思路:①把 n 个记录看成 n 个长度为1的有序子表:②进行两两归并使记录关键字有序,得到 n/2 个长度为 2 的有序子表: ③重复第②步直到所有记录归并成一个长度为 n 的有序表为止. Java代码 import java.util.Arrays; public class MergeSort { public static int[] sort(int[]

数据结构和算法-排序算法-归并排序

##################     归并排序        ####################### """ 归并算法逻辑 拆分 对整个序列进行拆分,左边一部分,右边一部分 然后对每一部分再次进行拆分,一直到拆分到只有一个元素,就到头了, 第1次拆分:54, 26, 93, 17, 77, 31, 44, 55, 第2次拆分:54, 26, 93, 17, 77, 31, 44, 55, 第3次拆分:54, 26, 93, 17, 77, 31, 44, 55

排序算法--归并排序

1.简介 归并算法是递归地将数组分成两个小数组,分别对两个数组进行排序,然后合并两个有序数组,递归的终止条件是要合并的两个数组分别只有一个元素. 合并两个有序数组的算法为: 取两个输入数组A,B和一个输出数组C,以及三个计数器Aptr,Bptr,Cptr,分别指向三个数组的开始位置: 比较A[Aptr],B[Bptr],取较小值存入C: 当两个输入表有一个用完时,则将另一个表中剩余部分拷贝到C中. 空间复杂度是O(N),时间复杂度是O(NlogN) 递归排序由于需要线性附加内存,在整个算法中还要