快速排序的原理就是以递归的方式进行划分
划分:从数组中选择一个数作为枢纽,将数组划分成两部分,一部分小于枢纽,一部分大于枢纽
这里列举三种快速排序,第一种是基本的快速排序。第二种优化枢纽选择方式,第三种优化长度较小数组的排序为插入排序。
一、选择最右为中枢的快速排序
步骤:
1,选择最右一个为枢纽。
2,划分整个数组。数组变成:[比枢纽小,...,枢纽,比枢纽大,...]
3,比枢纽小的部分递归1,2。
4,比枢纽大的部分递归1,2。
public static int[] data = {3,7,8,0,9,5,4,1,6,2}; /** * 交换位置 * @param i * @param j */ private static void swap(int i, int j){ int tmp = data[i]; data[i] = data[j]; data[j] = tmp; } /** * 递归 * @param leftIndex * @param rightIndex */ private static void recursion(int leftIndex, int rightIndex){ if(leftIndex >= rightIndex){ return; }else{ int pivot = data[rightIndex]; //以最右一个为枢纽 int pivotIndex = partition(leftIndex, rightIndex, pivot);//以pivot为枢纽进行划分两份,pivotIndex是最终枢纽的位置 recursion(leftIndex, pivotIndex - 1); //左侧再次递归划分 recursion(pivotIndex + 1, rightIndex);//右侧再次递归划分 } } /** * * 划分 * 以最右一个为枢纽,对“最左” 到“最右-1”进行划分; * 最终划分成两份,左份小于枢纽,右份大于枢纽,枢纽在中间 * @param leftIndex * @param rightIndex * @param pivot 枢纽 * @return 枢纽索引 */ private static int partition(int leftIndex, int rightIndex, int pivot){ /** 要划分区是leftIndex到rightIndex - 1。 */ int left = leftIndex - 1; //要划分区域最左-1 int right = rightIndex; //要划分区域最右+1 while(true){ while(data[++left] < pivot); //从最左往右遍历,找到一个大的 while(right > 0 && data[--right] > pivot); //从最右往左遍历,找到一个小的 if(left >= right){ break; }else{ swap(left, right); } } swap(left, rightIndex);//枢纽归位 return left; } public static void main(String[] args) { recursion(0, data.length - 1); System.out.println(Arrays.toString(data)); }
二、三数据项取中为中枢的快速排序
这种快速排序优化了中枢的选取,但是同时失去了对长度<=3的数组快速排序的能力
步骤:
1,对数组的三个值:第一个值(first)、最后一个值(last)、中间一个值(center),在对应的三个位置上排序,选中间一个为枢纽;最后枢纽和"最后-1"交换位置(即,将枢纽放在倒数第二个位置),数组变成:[三个较小......,枢纽,三个较大......]
2.1,<=3,手动排序
2.2,>3,划分整个数组。数组变成:[三个较小,比枢纽小......,枢纽,比枢纽大......,三个较大]
3,比枢纽小的部分递归1,2。
4,比枢纽大的部分1,2。
public static int[] data = {3,7,8,0,9,5,4,1,6,2}; /** * 交换位置 * @param i * @param j */ private static void swap(int i, int j){ int tmp = data[i]; data[i] = data[j]; data[j] = tmp; } /** * 由于长度小于等于3无法进行快速排序。 * 当长度小于等于3时直接手动排序,推出递归 * 对<=3的数组手动排序 * @param left * @param right */ private static void manualSort(int left, int right){ int size = right - left + 1; if(size <= 1){ return; } if(size == 2){ if(data[left] > data[right]){ swap(left, right); } }else{ if(data[left] > data[right - 1]){ swap(left, right - 1); } if(data[left] > data[right]){ swap(left, right); } if(data[right - 1] > data[right]){ swap(right - 1, right); } } } /** * 选择枢纽 * @param left * @param right * @return */ private static int medianOf3(int left, int right){ /** 从数组的开始,结束,和中间,对着在对应的三个位置上排序,枢纽放在right-1处,并返回枢纽 */ int center = (right + left) / 2; if(data[left] > data[center]){ swap(left, center); } if(data[left] > data[right]){ swap(left, right); } if(data[center] > data[right]){ swap(center, right); } /** 最后把居中的那个放在right-1处,作为枢纽 */ swap(center, right - 1);// return data[right - 1]; } /** * * 划分 * @param leftIndex * @param rightIndex * @param pivot * @return */ private static int partition(int leftIndex, int rightIndex, int pivot){ /** * leftIndex经过medianOf3已经是小的了 * rightIndex经过medianOf3已经是大的了 * rightIndex - 1 是枢纽 * 要划分的区域是leftIndex+1到rightIndex-2。 */ int left = leftIndex; //要划分区域最左-1 int right = rightIndex - 1; //要划分区域最右+1 while(true){ while(data[++left] < pivot); //从最左往右遍历,找到一个大的 while(data[--right] > pivot); //从最右往左遍历,找到一个小的 if(left >= right){ break; }else{ swap(left, right); } } swap(left, rightIndex - 1);//枢纽归位 return left; //返回枢纽位置 } /** * 递归 * @param leftIndex * @param rightIndex */ private static void recursion(int leftIndex, int rightIndex){ if(rightIndex - leftIndex + 1 <= 3){ manualSort(leftIndex, rightIndex);//手动排序 }else{ int pivot = medianOf3(leftIndex, rightIndex);//选择枢纽 int pivotIndex = partition(leftIndex, rightIndex, pivot);//以pivot为枢纽进行划分两份,pivotIndex是最终枢纽的位置 recursion(leftIndex, pivotIndex - 1); //左侧再次递归划分 recursion(pivotIndex + 1, rightIndex);//右侧再次递归划分 } } public static void main(String[] args) { recursion(0, data.length - 1); System.out.println(Arrays.toString(data)); }
三、较小数组改用插入排序的快速排序
将二中的手动排序改成插入排序,条件改成<10
public static int[] data = {3,7,8,0,9,5,4,1,6,2}; /** * 交换位置 * @param i * @param j */ private static void swap(int i, int j){ int tmp = data[i]; data[i] = data[j]; data[j] = tmp; } /** * 选择枢纽 * @param left * @param right * @return */ private static int medianOf3(int left, int right){ /** 从数组的开始,结束,和中间,对着在对应的三个位置上排序,枢纽放在right-1处,并返回枢纽 */ int center = (right + left) / 2; if(data[left] > data[center]){ swap(left, center); } if(data[left] > data[right]){ swap(left, right); } if(data[center] > data[right]){ swap(center, right); } /** 最后把居中的那个放在right-1处,作为枢纽 */ swap(center, right - 1);// return data[right - 1]; } /** * 插入排序 * @param left * @param right */ private static void insertionSort(int left, int right){ for(int i = left+1; i <= right; i++){ int temp = data[i]; int j = i - 1; while(j >= left && data[j] >= temp){ data[j + 1] = data[j]; j--; } data[j + 1] = temp; } } /** * * 划分 * @param leftIndex * @param rightIndex * @param pivot * @return */ private static int partition(int leftIndex, int rightIndex, int pivot){ /** * leftIndex经过medianOf3已经是小的了 * rightIndex经过medianOf3已经是大的了 * rightIndex - 1 是枢纽 * 要划分的区域是leftIndex+1到rightIndex-2。 */ int left = leftIndex; //要划分区域最左-1 int right = rightIndex - 1; //要划分区域最右+1 while(true){ while(data[++left] < pivot); //从最左往右遍历,找到一个大的 while(data[--right] > pivot); //从最右往左遍历,找到一个小的 if(left >= right){ break; }else{ swap(left, right); } } swap(left, rightIndex - 1);//枢纽归位 return left; //返回枢纽位置 } /** * 递归 * @param leftIndex * @param rightIndex */ private static void recursion(int leftIndex, int rightIndex){ if(rightIndex - leftIndex + 1 < 10){ insertionSort(leftIndex, rightIndex);//插入排序 }else{ int pivot = medianOf3(leftIndex, rightIndex);//选择枢纽 int pivotIndex = partition(leftIndex, rightIndex, pivot);//以pivot为枢纽进行划分两份,pivotIndex是最终枢纽的位置 recursion(leftIndex, pivotIndex - 1); //左侧再次递归划分 recursion(pivotIndex + 1, rightIndex);//右侧再次递归划分 } } public static void main(String[] args) { recursion(0, data.length - 1); System.out.println(Arrays.toString(data)); }
相关推荐
快速排序快速排序 快速排序 快速排序 快速排序 快速排序
快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序...快速排序快速排序快速排序快速排序快速排序快速排序快速排序快速排序
合并排序,插入排序,希尔排序,快速排序,冒泡排序,桶排序的C语言实现,原创。
全面的排序算法实现,包括插入排序、合并排序、堆排序、快速排序。 堆排序:HeapSort 讲解详见http://blog.csdn.net/fly_yr/article/details/8550701 插入排序:InSertion_Sort 讲解详见...
(1) 完成5种常用内部排序算法的演示,5种排序算法为:快速排序,直接插入排序,选择排序,堆排序,希尔排序; (2) 待排序元素为整数,排序序列存储在数据文件中,要求排序元素不少于30个; (3) 演示程序开始,...
数据结构(c语言版)严蔚敏 吴伟民编著 中直接插入排序、折半排序、shell排序、冒泡排序、快速排序、选择排序、堆排序的实现、归并排序,使用c语言实现
选择排序、插入排序、冒泡排序以及快速排序和归并排序的C语言实现,绝对可用
直接插入排序 选择排序 堆排序 归并排序 快速排序 冒泡排序等七种排序方法
快速排序源码 快速排序源码快速排序源码 快速排序源码快速排序源码 快速排序源码快速排序源码 快速排序源码快速排序源码 快速排序源码
直接插入排序 冒泡排序 快速排序 直接选择排序 堆排序 二路归并排序 C#源代码 使用C#实现的数据结构中的排序算法
冒泡排序,选择排序,插入排序,希尔排序,堆排序,归并排序,快速排序源码实现,里面有详细讲解,对新手应该有帮助
排序算法java版,速度排行:冒泡排序、简单选择排序、直接插入排序、折半插入排序、希尔排序、堆排序、归并排序、快速排序.mht
希尔排序,堆排序,快速排序,简单选择排序,插入排序,冒泡排序
快速排序,比较高效的排序算法之一。这是一个例子,一个关于快速排序的例子。
冒泡排序和快速排序的时间性能 冒泡排序和快速排序的时间性能 冒泡排序和快速排序的时间性能 冒泡排序和快速排序的时间性能 冒泡排序和快速排序的时间性能
快速排序、归并排序、基数排序等排序算法比较,比较时间性能,采用C++语言实现。。。
插入排序、冒泡排序、归并排序、快速排序四种排序方式的C++实现,各写成了一个函数,主函数中可以选择调用那一个。初始化数组时用的是随机种子srand((int)time(0))。在宏中定义数组大小。
(1) 冒泡排序和快速排序; (2) 插入排序和希尔排序; (3) 选择排序和堆排序; (4) 递归和非递归的归并排序。 2. 产生不同规模和分布的数据,以 Excel 生成算法执行时间 T(n)关于输入规模 n 的曲线的形式,...
舞动的排序算法 快速排序 通过动画演示快速排序,很好的学习,课程资源。
输入同样一组数据,比较直接插入排序、冒泡排序、快速排序这三种排序算法的关键字的比较次数和数据移动次数。