算法学习之快速排序
2010-12-20 22:01 MichaelYin 阅读(354) 评论(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。