归并排序(递归、非递归、以及自然归并排序)算法总结

注:本文所指归并排序指 二路归并排序。

归并排序是平均情况、最坏情况、最好情况时间复杂度都为O(Nlog2N)的稳定的排序算法。最近梳理了下归并排序的递归、非递归、以及自然归并排序算法。

归并排序的基础:将两个有序数组合并为一个有序数组,需要O(n)的辅助空间。

图片来自:https://www.cnblogs.com/chengxiao/p/6194356.html

// array:待排序数组

//temparray: 临时数组

//startindex:起始下标

//middleindex: 中间值下标

//endindex:终止下标

void merge(int sourcearray[], int temparray[], int startindex, int middleindex, int endindex)
{
int left = startindex, index = startindex;
int right = middleindex + 1 ;
if (left >= right )
return;

//对两有序数组进行合并
while (left != middleindex + 1 && right != endindex + 1)
{
if (sourcearray[left ] <= sourcearray[right ])
{
temparray[index++] = sourcearray[left++];
}
else
{
temparray[index++] = sourcearray[right++];
}
}

//左边数组未合并完,直接合入
while (left!= middleindex+ 1)
{
temparray[index++] = sourcearray[left++];
}

//右边数组未合并完,直接合入
while (right != endindex + 1)
{
temparray[index++] = sourcearray[right++];
}

//将临时数组中排好序的数组赋值给排序数组

for (int i = 0; i < endindex+ 1; ++i)
{
sourcearray[i] = temparray[i];
}

}

归并排序递归算法:

void mergesort(int sourcearray[],int temparray[], int low ,int high)

{

if (low>=high)

return;

//一分为二

int middle = (low+high)/2;

//左半部分递归

mergesort(sourcearray, temparray, low,middle);

//右半部分递归

mergesort(sourcearray, temparray, middle+1,high);

//将左半部分和右半部分合并

merge(sourcearray,temparray,low,middle,high);

}

非递归归并排序算法:

非递归排序与递归排序相反,将一个元素与相邻元素构成有序数组,再与旁边数组构成有序数组,直至整个数组有序。

void merge_noncursive(int sourcearray[], int temparray[],int endindex)

{

//步长,在i+step内数组有序,将sourcearray[i]...sourcearray[step-1]与sourcearray[i+step]...sourcearray[min(endindex,i+2*step-1)]两个有序数组合并起来。

int step = 1;

int index;

while(step <= endindex)

{

   index = 0;

  //将相邻数组合并

while(index <= endindex - 2*step +1)

{

  merge(sourcearray,temparray,index,index+step -1,index+2*step -1);

index += 2*step;

}

//合并有序的左半部分以及不及一个步长的右半部分

  if (index + step <= endindex)

{

    merge(sourcearray,temparray,index,index+step-1,endindex);

}

step *= 2;

}

}

自然归并排序:

既然归并排序是将多个有序的数组合并成一个数组,除了完全逆序的数组,总有一部分数组是有序的,我们可以获取有序数组的标记,从而将多个有序数组合并成一个有序数组。

//这个是理解自然归并排序的关键

int getindex(int array[], int flag[],int index)

{

int next = 0;

 //最开始为下标0

flag[next] = 0;

next++;

for(int i = 0;i<index;i++)

{

//找到数组元素不是有序的地方

if (array[i] > array[i+1])

{

  flag[next++] = i;

  }

}

//最后一位为最大下标

  flag[next] = index;

return next;

}

void merge_naturally(int sourcearray[],int temparray[],int index)

{

  int * flag = new int[index];

int num = getindex(sourcearray,flag,index);

//大于等于2说明除了0与index外有其他数,数组不完全有序

while(num >= 2)

{

    //对相邻有序数组进行合并

for(int i = 0; i<=num;i+=2)

    {

merge(sourcearray,temparray,flag[i],flag[i+1],flag[i+2]);

}

   //继续获取无序的序号

num = getindex(sourcearray,flag,index);

}

}

原文地址:https://www.cnblogs.com/gardener/p/9102985.html

时间: 2024-08-28 17:31:27

归并排序(递归、非递归、以及自然归并排序)算法总结的相关文章

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

首先,归并排序,分治,递归解决小的范围,再合并两个有序的小范围数组,便得到整个有序的数组. 这是很适合用递归来写的,至于非递归,便是从小到大,各个击破,从而使得整个数组有序.代码如下: 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&&

【算法拾遗】二分查找递归非递归实现

转载请注明出处:http://blog.csdn.net/ns_code/article/details/33747953 本篇博文没太多要说的,二分查找很简单,也是常见常考的查找算法,以下是递归非递归的实现. 非递归实现: /* 非递归实现,返回对应的序号 */ int BinarySearch(int *arr,int len,int key) { if(arr==NULL || len<1) return -1; int low = 0; int high = len-1; while(l

快速排序递归非递归队列堆栈实现

递归实现 #include<iostream> using namespace std; template <class T> void QuickSort(T A[],int left,int right) { if(left<right) { int i=left; int j=right+1; do { do i++;while(A[i]<A[left]); do j--;while(A[j]>A[left]); if(i<j) Swap(A[i],A

二叉树总结—建树和4种遍历方式(递归&amp;&amp;非递归)

今天总结一下二叉树,要考离散了,求不挂!二叉树最重要的就是 建立.4种遍历方式,简单应用,如何判断两颗二叉树是否相似 二叉树分为 :1.完全二叉树  2.满二叉树 结构性质: 1).满二叉树 高度为h ,节点数则为 2^h - 1,且叶子节点全在最下层,且叶子节点数为2^(n-1)个{n代表二叉树层数,也叫深度} 2).n个节点的 完全二叉树 深度为 int(log2n)(以2为底n的对数)+ 1: 3).非空二叉树 叶子节点个数==双分支节点数+1 4).非空二叉树 某节点编号 n  若有左孩

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

首先,归并排序,分治.递归解决小的范围.再合并两个有序的小范围数组,便得到整个有序的数组. 这是非常适合用递归来写的.至于非递归.便是从小到大.各个击破,从而使得整个数组有序.代码例如以下: 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

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

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

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

描述 [题解] 让区间的长度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

归并排序 - 递归非递归实现java

1.归并排序思想: 以2路归并为例,一个有n个记录的序列可以看作n个长度为1的有序子序列,将其两两合并成n/2(向上取整)个长度为2或1的有序序列,当有奇数个记录时为1,重复归并,直到得到一个长度为n的有序序列. 2.归并排序的复杂度: 递归:时间复杂度O(nlongn),空间复杂度O(n+longn) 非递归:时间复杂度O(nlongn),空间复杂度O(n) 所以用到归并排序,还是优先考虑非递归吧.  3.递归实现 1 public void mergeSort1(int[] data){ 2

排序算法 归并算法(递归+非递归)

部分理论和图来自:http://www.cnblogs.com/jingmoxukong/p/4308823.html  (侵删) 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. 归并排序的基本思想 将待排序序列R[0...n-1]看成是n个长度为1的有序序列,将相邻的有序表成对归并,

二叉树,递归非递归遍历算法(全)

包含了所有的非递归和递归的算法: #include<iostream> #include<queue> #include<stack> using namespace std; //二叉树结点的描述 typedef struct BiTNode { char data; struct BiTNode *lchild, *rchild; //左右孩子 }BiTNode,*BiTree; //按先序遍历创建二叉树 //BiTree *CreateBiTree() //返回结