首页 > 其他分享 >原地归并排序

原地归并排序

时间:2023-05-31 15:01:14浏览次数:33  
标签:归并 Reverse int void 原地 序列 排序


今天讨论的问题是Inplace Merge Sort,即原地归并排序。相比传统的归并排序,它的空间复杂度仅为

原地归并排序_i++


 

在原地归并排序中最主要用到了内存反转,即交换相邻的两块内存,在《编程珠玑》中又被称为手摇算法

内存反转是这样的:给定序列

原地归并排序_i++_02

,把它变为

原地归并排序_子序列_03

,要求空间为

原地归并排序_i++_04



分析:本问题的方法很经典,先对

原地归并排序_子序列_05

反转,再对

原地归并排序_子序列_06

反转,最后对

原地归并排序_子序列_07

整体     进行反转,这样就得到了

原地归并排序_子序列_03




原地归并排序原理介绍,以下面的数组为例进行说明。


原地归并排序_i++_09


开始时

原地归并排序_归并排序_10

分别指向这个数组的两个有序子序列的第一个值,然后

原地归并排序_归并排序_11

指针向后移动,直到找到比20大的值,即

原地归并排序_归并排序_11

移动到30,此时我们知道

原地归并排序_归并排序_11

指针之前的值一定是两个子序列的最小的块,先用一个临时指针

原地归并排序_i++_14

记录

原地归并排序_归并排序_15

的位置。然后把第二个序列的指针

原地归并排序_i++_16

向后移动,直到找到比30大的值,即

原地归并排序_i++_16

移动到55,即如下图所示:


原地归并排序_子序列_18


这样,我们把

原地归并排序_i++_19


原地归并排序_子序列_20

的内存块交换,再移动

原地归并排序_子序列_21

指针,移动长度为

原地归并排序_i++_22

,得到


原地归并排序_归并排序_23


这样可以看出

原地归并排序_子序列_21

之前的都已经排好序,而以

原地归并排序_子序列_21

开始的子序列和以

原地归并排序_i++_16

开始的子序列又是开始的问题模型,同样的操作进

行下去最终排序完成。



代码:


#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
const int N = 100005;

int a[N];

void swap(int a[],int x,int y)
{
    a[x] ^= a[y];
    a[y] ^= a[x];
    a[x] ^= a[y];
}

void Reverse(int a[],int x,int y)
{
    while(x < y)
        swap(a,x++,y--);
}

void Convert(int a[],int L,int M,int R)
{
    Reverse(a,L,M);
    Reverse(a,M+1,R);
    Reverse(a,L,R);
}

void Merge(int a[],int L,int M,int R)
{
    int i = L;
    int j = M + 1;
    while(i < j && j <= R)
    {
        while(i < j && a[i] <= a[j])
            i++;
        int index = j;
        while(j <= R && a[j] < a[i])
            j++;
        Convert(a,i,index-1,j-1);
        i += j - index;
    }
}

void Merge_Sort(int a[],int L,int R)
{
    if(L < R)
    {
        int M = L + (R - L) / 2;
        Merge_Sort(a,L,M);
        Merge_Sort(a,M+1,R);
        Merge(a,L,M,R);
    }
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        for(int i=0; i<n; i++)
            scanf("%d",&a[i]);
        Merge_Sort(a,0,n-1);
        for(int i=0; i<n; i++)
            printf("%d%c",a[i],i==n-1? '\n':' ');
    }
    return 0;
}




标签:归并,Reverse,int,void,原地,序列,排序
From: https://blog.51cto.com/u_16146153/6386951

相关文章

  • heapq 对有序的数组列表进行整体排序
     """功能:实现对有序的多个数组整体排序,获取topk个最小元素"""fromheapqimport*defheap_sort(arr,top_k):q=[]foriinrange(len(arr)):heappush(q,(arr[i][0],i,0))result=[]forkinrange(top_k):ifq:......
  • 结构体排序 sort排序
    首先,在学习c的时候,应该学了很多排序方法吧,类似于冒泡排序呀,选择排序,插入排序,快排呀等等,但是,在c++中,有一个很好的排序就是sort排序,在stl里面,sort排序可以说,无论是时间复杂度还是空间复杂度,都是很优化的,这就足以见证sort排序的强大了,也说明sort排序的重要性。在C++中使用sort()函数......
  • ES搜索排序,文档相关度评分介绍——Vector Space Model
    VectorSpaceModelThe vectorspacemodel providesawayof comparingamultitermqueryagainstadocument.Theoutputisasinglescorethatrepresentshowwellthedocumentmatchesthequery.Inordertodothis,themodelrepresentsboththedocumentan......
  • 排序(快排/归并/堆排/冒泡)
    912.排序数组稳定排序:如果a原本在b前面,且a==b,排序之后a仍然在b前面。非稳定排序:如果a原本在b前面,且a==b,排序之后a不一定在b前面。原地排序/非原地排序:区别在于是否使用额外的数组辅助排序快排快排不稳定平均时间复杂度\(O(n\logn)\)简单快......
  • qsort排序的用法
    //voidBubble_sort(intarr[],intsz)//{// inti=0;// for(i=0;i<sz-1;i++)//确定排序执行的次数// {// intj=0;// for(j=0;j<sz-1-i;j++)//确定每次排序两组元素的对比次数// {// inttmp=0;// if(arr[j]>arr[j+1])// {// tmp=......
  • mysql设置字段的排序规则对大小写敏感
    在开发中遇到一个问题:在插入一张表中提示主键冲突了,对数据分析了很久,没有发现问题。后面发现是数据库设计的时候设定的排序规则指定的是COLLATE=utf8_general_ci,而不是用COLLATE=utf8_bin,这两个规则的区别是什么呢?utf8_general_ci:这个排序规则是不区分大小写的,也就是说,在比......
  • 常用的排序算法总结
    常用的排序算法一、冒泡排序冒泡排序(BubbleSort),是一种较简单的排序算法。它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。这......
  • 33. 搜索旋转排序数组
    分析:A对于题目中定义的旋转数组,从中间一分为二。一定是被分为一个有序数组,一个旋转数组(循环数组)。B若对旋转数组再次从中间分割,会重复A的操作。对有序数组二分可看做普通二分查找一致操作。定理一:只有在顺序区间内才可以通过区间两端的数值判断target是否在其中。定理二:判......
  • 二叉排序链表C语言代码实现
    #include<stdio.h>#include<stdlib.h>#include<stdbool.h>typedefstructBSTNode{intdata;structBSTNode*lchild;structBSTNode*rchild;}BSTNode,*BSTree;BSTNode*InitNode(intdata){BSTNode*node=(BSTNode......
  • 二叉排序树的三种遍历方式和实现源代码
    二叉排序树(BinarySearchTree)是一种特殊的二叉树,它满足以下性质:对于树中的每个节点,其左子树中的所有节点的值都小于该节点的值,而右子树中的所有节点的值都大于该节点的值。这种特性使得对于二叉排序树的遍历具有一定的规律。前序遍历(PreorderTraversal)是一种遍历二叉树的方法。......