赞
踩
别急,首先给出快速排序一般算法,即快速排序的非随机基数算法。
/** * 快速排序算法 */ package quikesort; public class QuikeSort { public static int[] array = {49, 38, 65, 97, 76, 13, 27, 49}; public static void main(String[] args) { QuikeSort qs = new QuikeSort(); qs.quikeSort(array, 0, array.length - 1); for(int i = 0; i < array.length; i++) { System.out.print(array[i]+" "); } } /** * 分解数组,以基准(枢值)划分子数组,递归求解 * @param arr 待排序数组 * @param low 排序的起始位置 * @param high 排序的终止位置 */ public void quikeSort(int[] arr, int low, int high) { if(low < high) { //基准位置 int pivotLoc = partition(arr, low, high); //以基准划分为两个子数组,递归求解 quikeSort(arr, low, pivotLoc - 1); quikeSort(arr, pivotLoc + 1, high); } } /** * 一趟快速排序 * @return 返回当前基准位置 */ public int partition(int[] arr, int low, int high) { //确定基准,以此划分数组 int pivotkey = arr[low]; //将小于基准的数交换到左边区域,将大于基准的数交换到右边区域 while(low < high) { //从右往左,找到小于基准的数便停止,此时high指向该小于基准的数 while (low < high && arr[high] >= pivotkey) { --high; } arr[low] = arr[high]; //从左往右,找到大于基准的数便停止,此时low指向该大于基准的数 while (low < high && arr[low] <= pivotkey) { ++low; } arr[high] = arr[low]; } //一趟交换结束,此时low==high //将基准放入交换的最后一个位置 arr[low] = pivotkey; return low; } }
·
当排序的
序列很大 且 较为有序
时,可以进行一定的效率优化。注意仅在当前情况下可提高算法效率。
根据 快速排序算法的性能取决于划分的对称性
,修改基准的选择方法,使其选到中值或者接近中值,从而提高快速排序算法的效率。
由于未排序的数组中值未知,只能用随机选择方式增大每个元素作为基准的概率,而不是一味的选取相对固定位置上的元素(如a[p]、a[r]),尤其避免了数组本身可能是相对比较有序的情况带来的划分不均。而随机选择可以期望划分是比较对称的。
/** * 快速排序的随机基准算法 */ package randomquikesort; import java.util.Random; public class RandomQuikeSort { public static int[] array = {49, 38, 65, 97, 76, 13, 27, 49}; public static void main(String[] args) { RandomQuikeSort qs = new RandomQuikeSort(); qs.randomQuikeSort(array, 0, array.length - 1); for(int i = 0; i < array.length; i++) { System.out.print(array[i]+" "); } } /** * 分解数组,以基准(枢值)划分子数组,递归求解 * @param arr 待排序数组 * @param low 排序的起始位置 * @param high 排序的终止位置 */ public void randomQuikeSort(int[] arr, int low, int high) { if(low < high) { //基准位置 int pivotLoc = randomPartition(arr, low, high); //以基准划分为两个子数组,递归求解 randomQuikeSort(arr, low, pivotLoc - 1); randomQuikeSort(arr, pivotLoc + 1, high); } } /** * @see 一趟快速排序 * @return 返回当前基准位置 */ public int Partition(int[] arr, int low, int high) { //确定基准,以此划分数组 int pivotkey = arr[low]; //将小于基准的数交换到左边区域,将大于基准的数交换到右边区域 while(low < high) { //从右往左,找到小于基准的数便停止,此时high指向该小于基准的数 while (low < high && arr[high] >= pivotkey) { --high; } arr[low] = arr[high]; //从左往右,找到大于基准的数便停止,此时low指向该大于基准的数 while (low < high && arr[low] <= pivotkey) { ++low; } arr[high] = arr[low]; } //一趟交换结束,此时low==high //将基准放入交换的最后一个位置 arr[low] = pivotkey; return low; } /** * @see 随机获取基准 * @return 返回调用Partition:返回当前基准位置 */ public int randomPartition(int[] arr, int low, int high) { Random ran = new Random(); //在当前数组中产生随机基准,且摒弃最后一个元素 int randomPivotkey = ran.nextInt(high - low) + low; //将随机取得的基准交换到arr[low]以复用原Partition函数 swap(arr, low, randomPivotkey); return Partition(arr, low, high); } /** * 交换元素 */ public void swap(int[] arr, int x, int y) { int tmp = arr[x]; arr[x] = arr[y]; arr[y] = tmp; } }
只在main函数里测试,这里只给出mian函数的代码,其余代码未做修改同上。
/** * 快速排序算法时间测试 */ package quikesort; public class QuikeSortTimeTest { public static int[] m_arr = new int[10000]; public static void main(String[] args) { final int N = 10; //测试次数 long[] time = new long[N]; //记录多次的测试时长 for (int j = 0; j < N; j++) { for (int i = 0; i < m_arr.length; i++) { m_arr[i] = (int)(Math.random()*100)+1; //随机序列 //m_arr[i] = i; // 有序序列 //System.out.print(m_arr[i] + " "); } //System.out.print("\n"); QuikeSort qs = new QuikeSort(); // 开始时间 long startTime = System.currentTimeMillis(); qs.quikeSort(m_arr, 0, m_arr.length - 1); // 结束时间 long endTime = System.currentTimeMillis(); /* * for (int i = 0; i < m_arr.length; i++) { * System.out.print(m_arr[i] + " "); * } */ //System.out.print("\n"); //System.out.println(startTime); //System.out.println(endTime); time[j] = endTime - startTime; } System.out.print("基数不随机:"); long totalTime = 0; double averageTime = 0; //平均测试时长 for(int j = 0; j < N; j++) { System.out.print(time[j] + " "); // 输出总时长 totalTime += time[j]; } averageTime = totalTime / N; System.out.println("\n平均时长:" + averageTime); } ....非main函数代码同上,省略 }
/** * 快速排序的随机基准算法时间测试 */ package randomquikesort; import java.util.Random; public class RandomQuikeSortTimeTest { public static int[] m_arr = new int[100000]; public static void main(String[] args) { final int N = 10; //测试次数 long[] time = new long[N]; //记录多次的测试时长 for (int j = 0; j < N; j++) { for (int i = 0; i < m_arr.length; i++) { //m_arr[i] = (int)(Math.random()*10000)+1; //随机序列 m_arr[i] = i; // 有序序列 //System.out.print(m_arr[i] + " "); } //System.out.print("\n"); RandomQuikeSort rqs = new RandomQuikeSort(); // 开始时间 long startTime = System.currentTimeMillis(); rqs.randomQuikeSort(m_arr, 0, m_arr.length - 1); // 结束时间 long endTime = System.currentTimeMillis(); /* * for (int i = 0; i < m_arr.length; i++) { * System.out.print(m_arr[i] + " "); * } */ //System.out.print("\n"); //System.out.println(startTime); //System.out.println(endTime); time[j] = endTime - startTime; } System.out.print("基数随机:"); long totalTime = 0; double averageTime = 0; //平均测试时长 for(int j = 0; j < N; j++) { System.out.print(time[j] + " "); // 输出总时长 totalTime += time[j]; } averageTime = totalTime / N; System.out.println("\n平均时长:" + averageTime); } //....非main函数代码同上,省略 }
这里只给出关键的测试过程及结果。
public static int[] m_arr = new int[100000]; //100000个元素的快速排序
for (int i = 0; i < m_arr.length; i++) {
m_arr[i] = (int)(Math.random()*100)+1; //随机序列 1~100
}
多组测试的平均时长大概稳定在16毫秒:
多组测试的平均时长大概稳定在23毫秒:
增加随机范围,扩大序列元素的随机性:
for (int i = 0; i < m_arr.length; i++) {
m_arr[i] = (int)(Math.random()*10000)+1; //随机序列 1~10000
}
这里只给出完全有序序列的测试,较有序时的测试结果与此相同。只需在有序序列的基础上修改某些元素值即可。
public static int[] m_arr = new int[10000]; //10000个元素的快速排序
for (int i = 0; i < m_arr.length; i++) {
m_arr[i] = i; // 有序序列
}
多组测试的平均时长大概稳定在13毫秒:
多组测试的平均时长大概稳定在1毫秒:
当数组元素随机无序时,由于快速排序随机基数算法需要产生随机元素的下标,并与排序序列的首元素交换位置,此时相对于非随机基数的一般性快速排序算法耗时较长,由于数组元素本身随机性较强,其优化算法的基准随机性并未体现。
序列元素的随机范围影响快速排序的性能。
当数据量大且基本有序时,与一般快速排序算法相比,此时优化算法基准的随机性得以体现,测试结果显示其耗时更短,效率优化提升非常明显。
需要排序的大量较有序数据,且该数据较稳定的情况下,应用十分广泛。例如,按照播放量排序的热门歌曲排行榜,一般以一周的周期来更新,本身是在有序的情况下进行的排名变动,且变动相对稳定,歌曲数据量很大,此时用随机基准的快速排序效率就比较高了。诸如此类等等的排行榜,在当今大数据、智能推荐和数据排名分析的背景下,这种较规则排序的应用是非常广泛和重要的。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。