【书上讲解】归并排序的非递归写法

描述

【题解】

让区间的长度L为1,2,4,...2^(n-1)
然后对每个位置i开始的长度为L的区间归并有序,用归并排序的方法就好,然后i跳转到i+L
复杂度仍然是log2(n)*n级别的,注意写的时候的一些细节。
比如一定要让最后L>=n的情况进行过一次,不然无法保证整个序列是有序的

【代码】

/*
    归并排序非递归写法
*/
#include <cstdio>
const int N = 1e5;

int a[N+10],b[N+10];
int n;

//把a这个数组在l1..r2这个区间分成两段[l1,r1]和[l2,r2];然后进行合并
void _Merge(int a[],int b[],int l1,int r1,int l2,int r2){
    int i = l1,j = l2,k = l1;
    while (i<=r1 && j<= r2){
        if (a[i]<=a[j])
            b[k++]=a[i++];
        else
            b[k++] = a[j++];
    }
    while (i<=r1) b[k++] = a[i++];
    while (j<=r2) b[k++] = a[j++];
}

void _merge(int a[],int b[],int L){
    int i = 1;
    while (i+L-1<n){//把i..i+L-1这个区间合并
        _Merge(a,b,i,i+L/2-1,i+L/2,i+L-1);
        i = i+L;
    }
    //i+L-1>=n
    if (i+L/2-1<=n){
        _Merge(a,b,i,i+L/2-1,i+L/2,n);
    }else{
        _Merge(a,b,i,n,n+1,n);
    }
}

int main(){
    //freopen("D:\\rush.txt","r",stdin);
    scanf("%d",&n);
    for (int i = 1;i <= n;i++) scanf("%d",&a[i]);
    int L = 1;
    while (L<=n){
        L*=2;
        _merge(a,b,L);//把a长度为L的合并起来然后放到b数组中去
        L*=2;//要确保L>n的时候,那个长度合并过
        _merge(b,a,L);//把b长度为L的合并起来然后放到a数组中去
    }
    for (int i = 1;i <= n;i++) printf("%d ",a[i]);
    return 0;
}

原文地址:https://www.cnblogs.com/AWCXV/p/11620700.html

时间: 2024-08-29 17:02:54

【书上讲解】归并排序的非递归写法的相关文章

二叉树前序、中序、后序遍历非递归写法的透彻解析

前言 在前两篇文章二叉树和二叉搜索树中已经涉及到了二叉树的三种遍历.递归写法,只要理解思想,几行代码.可是非递归写法却很不容易.这里特地总结下,透彻解析它们的非递归写法.其中,中序遍历的非递归写法最简单,后序遍历最难.我们的讨论基础是这样的: //Binary Tree Node typedef struct node { int data; struct node* lchild; //左孩子 struct node* rchild; //右孩子 }BTNode; 首先,有一点是明确的:非递归

快速排序 归并排序的非递归版本 备忘

首先,归并排序,分治,递归解决小的范围,再合并两个有序的小范围数组,便得到整个有序的数组. 这是很适合用递归来写的,至于非递归,便是从小到大,各个击破,从而使得整个数组有序.代码如下: void merge(vector<int> &A, int left, int mid, int right) { int i=left,j=mid+1; vector<int> tmp(right-left+1,0); int k=0; while(i<=mid&&

【数据结构】线索化二叉树中序线索化的递归写法和非递归写法

二叉树是一种非线性结构,遍历二叉树几乎都是通过递归或者用栈辅助实现非递归的遍历.用二叉树作为存储结构时,取到一个节点,只能获取节点的左孩子和右孩子,不能直接得到节点的任一遍历序列的前驱或者后继. 为了保存这种在遍历中需要的信息,我们利用二叉树中指向左右子树的空指针来存放节点的前驱和后继信息.所以引入了线索化二叉树.下面我们讲一下线索化二叉树中序线索化的两种实现方法: (1).递归实现中序线索化二叉树 首先我们先看一下线索化二叉树的结构 enum PointerTag{ THREAD, LINK 

二叉树中序遍历非递归写法

中序遍历比前序要稍微复杂些,我也先用手写理出思路 代码写的和书上的一比...感觉麻烦了好多,但毕竟是自己理的思路不容易忘,所以还是贴自己的 void inOrder_stack(BiTree T){ printf("\n非递归中序遍历结果:\n"); initStack(&sqStack); BiTree p=T,l;//l用于保存上次的输出 push(&sqStack,p); while(!stackEmpty(sqStack)){ getTop(&sqSta

史上最简明易懂非递归遍历二叉树算法

巧若拙(欢迎转载,但请注明出处:http://blog.csdn.net/qiaoruozhuo) 遍历二叉树的递归函数是体现了算法之美的高妙算法,思路清晰,代码简洁,读之赏心悦目.代码例如以下: 程序代码: void PreOrderTraverse_R(BiTree BT)//採用递归方式先序遍历二叉树BT { if(BT != NULL) { printf("%c", BT->data);//输出该结点(根结点) PreOrderTraverse_R(BT->lchi

高速排序 归并排序的非递归版本号 备忘

首先,归并排序,分治.递归解决小的范围.再合并两个有序的小范围数组,便得到整个有序的数组. 这是非常适合用递归来写的.至于非递归.便是从小到大.各个击破,从而使得整个数组有序.代码例如以下: void merge(vector<int> &A, int left, int mid, int right) { int i=left,j=mid+1; vector<int> tmp(right-left+1,0); int k=0; while(i<=mid&&a

二叉树前序遍历非递归写法

前序遍历非递归依靠栈实现,相对来说比较简单,先来用手写模拟一下基本就能知道怎么写了 据此可得如下代码 void preOrder_stack(BiTree T){ printf("\n非递归先序遍历结果:\n"); initStack(&sqStack); BiTree p=T; push(&sqStack,p); while(!stackEmpty(sqStack)){ pop(&sqStack,&p); printf("%d ",

【Java】 归并排序的非递归实现

归并排序可以采用递归方法(见:归并排序),但递归方法会消耗深度位O(longn)的栈空间,使用归并排序时,应该尽量使用非递归方法.本文实现了java版的非递归归并排序. 更多:数据结构与算法合集 思路分析 递归排序的核心是merge(int[] arr, int start, int mid, int end)函数,讲[start~mid-1]和[mid~end]部分的数据合并,递归代码是使用递归得到mid,一步步分解数组. 非递归时,我们直接定义要合并的小数组长度从1开始,在较小的长度数组都合

二分查找的递归和非递归写法

一.概述 二分查找是针对有序数列的,对无序数列是无效的,在有序序列中使用二分查找能大大提高查找效率,通常能将时间按复杂度从O(n)降至O(logn). 二.查找某数的位置(或存在性) 递归: 1 //返回"-1"表示为找到 2 //否则返回目标的下标(若有多个,只是其中一个) 3 int binary_searchs(int *arr, int target, int l, int r) 4 { 5 if (l > r) return -1; 6 int mid = (l + r