您的位置:首页 > 编程语言 > Java开发

java中归并排序算法的递归与迭代

2014-09-21 13:53 316 查看
归并排序(merge sort)算法的思想是(以数组为例)将一个要排序的数组分为两半,对这两半分别排序,再将它们归并为一个有序数组。这是一种采用分治法的算法,就是将一个问题分解成两个或更多个规模更小但却截然不同的问题,分别解决每个新问题,再将它们的解法组合起来解决原问题。综上所述,归并排序主要分为两个步骤:一是如何将要排序的数组进行划分;二是如何已经排好序的数组合并为原来的数组。下面是基于递归与迭代的归并排序算法的设计。
基于递归的merge sort

基本思路:将一个要排序的数组,按序号分成原数组的两半(为了合并的方便,要保证划分后的数组序号是连续的),对这两半分别排序,将排序后的两个数组合并为一个临时数组,最后将这个临时数组复制回原数组。(注:划分后的两个数组继续使用划分的方法进行划分,只到每个数组中只含一个元素为止)

算法实现:

/**
* 这一步主要是为了隐藏临时数组
* @param Array
* @param first
* @param last
*/
public void mergeSort(T[] Array,int first,int last)
{
T[] tempArray=(T[])new Comparable<?>[Array.length];
mergeSort(Array,tempArray,first,last);
}
/**
* 归并排序
* @param Array  原数组
* @param tempArray  临时数组
* @param first  要排序数组的起始序号
* @param last   要排序数组的结束序号
*/
public void mergeSort(T[] Array,T[] tempArray,int first,int last)
{

if(first<last)
{
int mid=(first+last)/2;
mergeSort(Array,tempArray,first,mid);
mergeSort(Array,tempArray,mid+1,last);
merge(Array,tempArray,first,mid,last);
}
}
/**
* 将已经排好序的数组通过临时数组合并成原来的数组
* @param Array   原数组
* @param tempArray  临时数组
* @param first   要排序数组的起始序号
* @param mid     将数组分割成两半的序号
* @param last    要排序数组的结束序号
*/
public void merge(T[] Array,T[] tempArray,int first,int mid,int last)
{
int leftIndex=first;
int rightIndex=mid+1;
int i=first;
while(leftIndex<=mid&&rightIndex<=last)
{
if(Array[leftIndex].compareTo(Array[rightIndex])<0)
{
tempArray[i]=Array[leftIndex];
leftIndex++;
}
else
{
tempArray[i]=Array[rightIndex];
rightIndex++;
}
i++;
}
// 将左半边剩余的数组复制到临时数组中
while(leftIndex<=mid)
{
tempArray[i++]=Array[leftIndex++];
}
// 将右半边剩余的数组复制到临时数组中
while(rightIndex<=last)
{
tempArray[i++]=Array[rightIndex++];
}
// 将临时数组复制回原数组
for(int j=first;j<=last;j++)
{
Array[j]=tempArray[j];
}
}
基于迭代的merge sort

基本思路:从数组的始端开始,将每一对单个元素归并为含有两个元素的子数组,然后回到数组的始端,将每一对含有两个元素的子数组归并为含有4个元素的子数组,以此类推。注:归并两个子数组需要一个额外的临时数组,尽管使用这额外的数组的空间是必需的,但可以通过一定的技巧节省递归中消耗在将元素从临时数组复制回原数组的大部分时间。

算法实现:

/**
* 将Array中的子数组归并到tempArray中,不需要将tempArray复制到Array中,而是将tempArray的子数组归并到Array中
* @param Array
* @param first
* @param last
*/
public void mergetionSort(T[] Array,int first,int last)
{
T[] tempArray=(T[])new Comparable<?>[Array.length];
int step=1;
while(step<last)
{
mergePass(Array,tempArray,step,first,last);
for(int i=0;i<tempArray.length;i++)
System.out.print(tempArray[i]+" ");
System.out.println();
step*=2;
mergePass(tempArray,Array,step,first,last);
for(int i=0;i<Array.length;i++)
System.out.print(Array[i]+" ");
System.out.println();
step*=2;
}
}

/**
* 对Array表按子表步长为step, [0,step-1],[step,step*2-1],归并到MergeList中
* @param Array   原数组
* @param tempArray 临时数组
* @param step  步长从1开始,然后按2的倍数进行递增(即指子数组中的元素)
*/
public void mergePass(T[] Array,T[] tempArray,int step,int first,int last)
{
int index=first;//下一个待归并段开始指针
while(index<=last)
{
//剩余元素存在两个待归并长度的元素
if(index+2*step<=(last+1))
{
merge2(Array,tempArray,index,index+step-1,index+step*2-1);
index=index+2*step;  //将指针进行迭代
}
//剩余元素存在一个待归并长度的元素和一个小于其归并长度的元素
else if(index+step<=(last+1))
{
merge2(Array,tempArray,index,index+step-1,last);
index=last+1;
}
//存在一个小于其归并长度的元素
else
while(index<=last)
{
tempArray[index]=Array[index];
index++;
}
}
}
/**
* 将已经排好序的数组通过临时数组合并成原来的数组
* @param Array   原数组
* @param tempArray  临时数组
* @param first   要排序数组的起始序号
* @param mid     将数组分割成两半的序号
* @param last    要排序数组的结束序号
*/
public void merge2(T[] Array,T[] tempArray,int first,int mid,int last)
{
int leftIndex=first;
int rightIndex=mid+1;
int i=first;
while(leftIndex<=mid&&rightIndex<=last)
{
if(Array[leftIndex].compareTo(Array[rightIndex])<0)
{
tempArray[i]=Array[leftIndex];
leftIndex++;
}
else
{
tempArray[i]=Array[rightIndex];
rightIndex++;
}
i++;
}
// 将左半边剩余的数组复制到临时数组中
while(leftIndex<=mid)
{
tempArray[i++]=Array[leftIndex++];
}
// 将右半边剩余的数组复制到临时数组中
while(rightIndex<=last)
{
tempArray[i++]=Array[rightIndex++];
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: