五、归并排序
所谓归并,是指将两个已排序的序列,比较合并形成一个已排序列,又称两路归并。
思路:归并排序有两种思想,一种是自底向上的方法,一种是自顶向下的方法。
自底向上的基本思想是:第一趟归并时,将待排序的文件看做是n个长度为1的有序子文件,将这些子文件两两归并。
将归并后的子文件两两归并,如此反复,得到最后长度为n的有序文件为止。
自顶向下的基本思想是:采用分治法。
步骤:这里采用自底向上的方法解决归并。
1.归并算法,设置i,j,m三个指针,起初值分别指向这三个记录区间的起始位置。合并时一次比较mat[i]和mat[j]的关键字,
取关键字较小的记录复制到动态分配的table[m]中,然后将被复制的指针+1,再将m+1。重复这一过程直至两个输入的子
文件有一个已全部复制完毕,此时另一个非空子文件复制到table中。
2.一趟归并算法,在某趟归并中,必须考虑子文件的奇偶,如果子文件数为奇数,则最后一个子文件无需和其他子文件归并。
如果子文件数为偶数,则要注意最后一对子文件中后一个子文件的区间上界是n。
3.二路归并排序,
描述:
设计:
Code
using System;
public class myMergeSort
{
private int[] mat;
public myMergeSort(int[] table)
{
mat=new int[table.Length];
table.CopyTo(mat,0); //数组拷贝
}
public void output()
{
for(int i=0;i<mat.Length;i++)
Console.Write(mat[i]+" ");
Console.WriteLine();
}
public void mergeSort()
{
for(int len=1;len<mat.Length;len*=2)
mergePass(len);
}
public void merge(int low,int m,int high)
{
int i=low,j=m+1,k=0; //初始化下标
int[] table = new int[high-low+1]; //申请和
while(i<=m && j<=high) //将较小的数放入tmp数组
{
table[k++]=mat[i]<=mat[j]?mat[i++]:mat[j++];
}
while(i<=m) //前一个序列剩余的数放入tmp数组
{
table[k++]=mat[i++];
}
while(j<=high) //后一个序列剩余的数防御tmp数组
{
table[k++]=mat[j++];
}
table.CopyTo(mat,low);
/*
for(k=0,i=low;i<=high;i++,k++) //归并完成后将结果复制回mat数组
mat[i]=table[k];
*/
}
public void mergePass(int len)
{
int i;
for(i=0;i+2*len<mat.Length;i+=2*len)
merge(i,i+len-1,i+2*len-1);
if(i+len-1<mat.Length)
merge(i,i+len-1,mat.Length-1);
}
public static void Main()
{
/* 成功
#region 测试方法merge()
int[] table = {1,4,8,2,3,6};
myMergeSort mms=new myMergeSort(table);
mms.output();
mms.merge(0,2,5);
mms.output();
#endregion
*/
#region 测试方法mergeSort()方法
Random rom = new Random();
int[] table = new int[10];
for(int i=0;i<table.Length;i++)
table[i]=rom.Next(1,99); //生成随数放入数组。
myMergeSort mms = new myMergeSort(table);
mms.output();
mms.mergeSort();
mms.output();
#endregion
}
}
排序我就复习到这里,后面还有箱排序、桶排序、基数排序,没有接触过,以后学习。通过这些天的排序的复习,我发现自己
很多的不足,几个基本的排序自己都不是了然于胸,还要翻看书才能找到细微的出错。所以说掌握一点东西真的不容易,不是你觉得
你自己会了,你就会了。看懂了,也不是真正的懂了。必须把握到每一个细节,才能说自己清楚了。接下来复习相对会快一点了,因为
快开学了,还有很多的事要做。