算法学习之快速排序
2010-12-20 22:01 MichaelYin 阅读(357) 评论(0) 收藏 举报快速排序通常是用于排序的最佳实用选择,因为它的平均性能相当好。
快速排序和先前讲到的合并排序一样,体现了算法设计中的分治的思想。我们首先将问题进行分解,将数组划分成两个部分A[p…q-1]和A[q+1…r],使得A[p…q-1]中的元素小于等于A[q],然后分别解决前面一个数组和后面一个数组的排序,最后进行合并,由于这两个数组是就地排序(in place)的,所以不用像合并排序中一样进行过多的合并的操作。
由于中间的分别排序的部分可以使用递归实现,所以快速排序中关键的地方就是如何将数组进行分解了。
/// <summary>
/// 对数组进行分组,返回分界处的index
/// </summary>
public static int Partition(int[] array, int firstIndex, int secIndex)
{
int key = array[secIndex];
int k = firstIndex;
for (int j = firstIndex; j < secIndex; j++)
{
if (array[j] < key)
{
Utils.Swap(ref array[k], ref array[j]);
k++;
}
}
//将最后一个元素和对应的分解出的元素互换
Utils.Swap(ref array[k], ref array[secIndex]);
return k;
}
先将最后一位的值取出来作为比较的Key,k左边全部是小于Key的值,由于开始还没有比较,所以k = firstIndex,如果发现有小于Key的值就和K指向的数进行替换,并且k值加1,最后的情况就是k左边的值就都比Key小,最后一行的Utils.Swap(ref array[k], ref array[secIndex]);将含有Key的值移到了中间,这样就实现了拆分数组并且前面小于等于A[k]的值。下面是快速排序的代码
public static void Sort(int[] array, int firstIndex, int secIndex)
{
if (firstIndex < secIndex)
{
int index = RandomPartition(array, firstIndex, secIndex);
//递归调用
Sort(array, firstIndex, index - 1);
Sort(array, index + 1, secIndex);
}
}
下面就快速排序还顺带讲一点随机化的知识,虽然我们假定输入数据的所有排列顺序都是等可能的,但是在实际工程中,这个假设不一定总是成立,所以,我们需要在算法中人为的加入随机化成分,以便对于所有输入,它能获得较好的平均情况性能。
public static int RandomPartition(int[] array, int firstIndex, int secIndex)
{
//从中随机选出一个index,然后和最后一个元素互换
int j = RandomFactory.GetRandomInt(firstIndex, secIndex);
Utils.Swap(ref array[j], ref array[secIndex]);
return Partition(array, firstIndex, secIndex);
}
原理其实很简单,就是在分解之前随机的从数组中选取一个数和最后一个元素互换,这样的本质就是数组中的任何一个元素都有可能作比较的那个Key。
浙公网安备 33010602011771号