您的位置:首页 > 其它

使用插入排序优化快速排序的算法实现

2008-01-26 10:46 579 查看
实验目的:
快速排序可以按照以下的算法思想优化,并加快快速排序的速度:即当快速排序所划分的子序列的长度小于某个定值k时,该子序列基本有序,可以采用插入排序的办法对子序列进行排序,从而使整体算法的时间复杂度的期望下降为O(nk+nlg(n/k))。本实验的目的是实现该快速排序的优化算法,并且探讨合理的k的取值范围
问题定义
实验总共要解决两个问题
1、 优化的快速排序的算法确实能够加速快速排序的速度。
2、 讨论k的合理的取值范围。
对于给定规模为n的int[]无序随机数组进行排序,通过实验证明经过优化的快速排序比传统的快排效率要高,并讨论k的值的范围。
实验思想
1、 优化快速排序的方法:
a) 在快速的排序的方法中加入判断语句,当high-low<k的时候则调用插入排序的算法,否则继续使用快速排序。
b) 当k<=2时,实质上不调用插入排序,这样就可以得出相同规模的情况下直接使用快速排序所需要的时间。从而便于比较
2、 通过考察时间消耗来确定性能的高低
a) 每次计算数据都取一定规模的int 32型无序随机数进行排序,为了避免误差,规模n一定时,不同的k值,都计算5次运算时间,取平均值记录。
b) 使用.net framework 2.0提供的Stopwatch计时器对象,该对象可以将时间间隔精确到0.0001ms。
c) 从理论上得到合理的k值的取值范围是k<=logn.因此在验证取值范围的时候要取到log n 两侧的值。
d) 通过比较时间复杂度来计算性能提升的多少,从而得到加快了快速排序的结论,以及合理的k的取值范围。
测试数据及结果
本测试的硬件以及软件环境如下
CPU:PM 1.5G; 内存:768M;操作系统:windows xp sp2;软件平台:.net 2.0;
1、 数组规模为50的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms。



2、 数组规模为500的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms。



整体图



[align=center]局部图[/align]
3、 数组规模为5000的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms



4、 数组规模为50000的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms



5、 数组规模为1,000,000的时候得到如下数据。
其中第一行为k的取值、第二行为程序运行所需要的时间,单位为ms



结果分析:
1、 由所有的图可以看出,经过优化以后的快速排序比传统快速排序的速度要快,通过数据计算可以排序速度提高了10%-20%左右。
2、 通过图示也可以知道当k=logn的时候,其效率提升并不是最大的,在规模不大(例如5个数量级以下)的排序中其最佳的k的取值往往比log n大,一般以8—12之间为最小。
当规模较大时,一般取logn为宜,即使最佳取值超过logn其性能提升也不明显。
3、 此后随着k的取值的增大,尤其是超过50之后,时间复杂度明显提升,甚至比快速排序的算法要差。
4、 在规模较大的排序过程中快速排序的效率明显好于插入排序。
有可能影响结论的因素:
1、 快速取随机数的算法:
a) 在本实验中,所使用的随机数是在10n的整数内取n个无重复的随机数,该算法有可能会影响对实验结果的分析有轻微影响。
2、 小规模的数组的分析
a) 对于小规模的数组有可能在快速排序之后得到的子序列的长度小于8,因此直接取8值得商榷。

实验结论
1、 经过优化以后的快速排序比传统快速排序的速度要快,通过数据计算可以排序速度提高了10%-20%左右。
2、 在规模不大(例如5个数量级以下)的排序中其最佳的k的取值往往比log n大,一般以8—12之间效率最佳。
当规模较大时,k的取值一般取logn为宜,即使最佳取值超过logn其性能提升也不明显。

源代码
优化排序的算法源代码(C#描述)


class SortOp




...{ //插入排序


private static void InsertSort(int[] list,int low,int high)




...{


for (int i = low; i < high; i++)




...{


int t = list[i];


int j = i;


while ((j > 0) && (list[j - 1] > t))




...{


list[j] = list[j - 1];


--j;


}


list[j] = t;


}


}








private static void Swap(ref int i, ref int j)


//只有两个元素时直接交换




...{


int t;


t = i;


i = j;


j = t;


}


//快速排序优化


public static void QuickSort(int[] list, int low, int high,int k)




...{


//只剩下一个无需交换


if (high <= low)




...{


return;


}


else if (high == low + 1)




...{


//只剩下两个直接交换


if (list[low] > list[high])




...{


Swap(ref list[low], ref list[high]);


return;


}


}


//大于三个元素开始优化的快速排序


myQuickSort(list, low, high,k);


}




public static void myQuickSort(int[] list, int low, int high,int k)




...{


if (low < high)




...{


if(high-low<k) //子序列小于k个使用插入排序




...{


InsertSort(list,low,high);


}




else...{


int pivot = Partition(list, low, high);


myQuickSort(list, low, pivot - 1,k);


myQuickSort(list, pivot + 1, high,k);


}


}


}




private static int Partition(int[] list, int low, int high)




...{


int pivot;


pivot = list[low];


while (low < high)




...{


while (low < high && list[high] >= pivot)




...{


high--;


}


if (low != high)




...{


Swap(ref list[low], ref list[high]);


low++;


}


while (low < high && list[low] <= pivot)




...{


low++;


}


if (low != high)




...{


Swap(ref list[low], ref list[high]);


high--;


}


}


return low;


}




}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: