赞
踩
从待排序的关键字中选取一个关键字,将小于该关键字的移到前面,而将大于该关键字的移到后面,结果将待排序记录序列分为两个子表,最后将该关键字插到其分界线处。这个过程称为一趟快速排序。然后对两个子表继续进行快速排序。
1)选择一个基准值(选择最右区间,最右边的数作为基准值) 选择基准值的方法有取边法、随机法和三数取中法。
2)遍历整个区间,每个数都和基准值做比较,并且发生一定交换。(partition的方法有hover法、挖坑法和前后下标法)
遍历结束后,使得
比基准值小的数(包括等于)都在基准值的左边
比基准值大的数(包括等于)都在基准值的右边
3)分治算法
分别对左右两个小区间进行同样的方式处理,直到小区间的size==0或者size==1
切割的算法分析:
1)hover法:
从左边找比基准值大的数,从右边找比基准值小的数。然后交换这两个数,直到begin==end,再将基准值插入到begin中。
2)挖坑法:
先记录基准值,然后从左边选出比基准值大的数,将该数填到基准值的位置上,接着从右边遍历,找出比基准值小的数,填到begin的位置上。直到begin==end,最后将基准值填到begin的位置上。
3)前后下标法:
设置两个下标引用:d和i,保证d前面的数都比基准值小(只要array[i]<pivot,就交换d和i对应的元素)[d,i]无序,直到i==right,则d的位置就是基准值的位置,将arr[d]和arr[right]交换。
- public class QuickSort {
- private static void quickSort(int[] array){
- quickSortIR(array,0,array.length-1);
- }
- //[left,right]
- private static void quickSortIR(int[] array, int left, int right) {
- //终止条件 区间里只有一个或者没有
- if(left>=right){
- return;
- }
- //1.取基准值
- int key=array[right];
- //2.分割
- int pivotIndex=partition3(array,left,right);//返回基准值在的下标
-
- //[left,pivotIndex-1]:比基准值小的数 [pivotIndex+1,right]:比基准值大的数
- quickSortIR(array,left,pivotIndex-1);
- quickSortIR(array,pivotIndex+1,right);
- }
- //分割 hover法 从左边找比基准值大的数,从右边找比基准值小的数。然后交换这两个数,直到begin==end,再将基准值插入到begin中。
- private static int partition1(int[] array, int left, int right) {
- int begin=left;
- int end=right;
- int pivot=array[right];
- while(begin<end){
- while(begin<end&&array[begin]<=pivot){
- begin++;
- }
- while(begin<end&&array[end]>=pivot){
- end--;
- }
- swap(array,begin,end);
- }
- //begin==end 则基准值要插入的位置是array[begin],交换两个数
- swap(array,begin,right);
- return begin;
- }
- //挖坑法 先记录基准值,然后从左边选出比基准值大的数,将该数填到基准值的位置上,接着从右边遍历,找出比基准值小的数,填到begin的位置上。
- //直到begin==end,最后将基准值填到begin的位置上。
- private static int partition2(int[] array,int left,int right){
- int pivot=array[right];
- int begin=left;
- int end=right;
- while(begin<end){
- while(begin<end&&array[begin]<=pivot){
- begin++;
- }
- array[end]=array[begin];
- while(begin<end&&array[end]>=pivot){
- end--;
- }
- array[begin]=array[end];
- }
- array[begin]=pivot;
- return begin;
- }
- //前后下标法 设置两个下标引用,d和i,保证d前面的数都比基准值小(只要array[i]<pivot,就交换d和i对应的元素)[d,i]无序,直到i==right,则d的位置就是基准值的位置,将arr[d]和arr[right]交换。
- private static int partition3(int[] array,int left,int right){
- int d=left;
- for(int i=left;i<=right;i++){
- if(array[i]<array[right]){
- swap(array,i,d);
- d++;
- }
- }
- swap(array,d,right);
- return d;
- }
- private static void swap(int[] array, int begin, int end) {
- int temp=array[begin];
- array[begin]=array[end];
- array[end]=temp;
- }
-
- public static void main(String[] args) {
- int[] array=new int[]{33,4,8,3,10,21,9,4};
- quickSort(array);
- for(int item:array){
- System.out.print(item+" ");
- }
- }
- }

取基准值还有三数取中法,取值的代码为:
- //返回三数取中的下标
- private static int sanshuQuZhong(int[] array,int left,int right){
- int mid=left+(right-left)/2;
- if(array[left]>array[right]){
- if(array[left]<array[mid]){
- return left;
- }else if(array[mid]>array[right]){
- return mid;
- }else{
- return right;
- }
- }else{
- if(array[right]<array[mid]){
- return right;
- }else if(array[mid]>array[left]){
- return mid;
- }else{
- return left;
- }
- }
- }
- private static void quickSortInnerSan(int[] array, int left, int right) {
- //直到size==1或size==0
- if(left==right){
- return;//size==1
- }
- if(left>right){
- return;//size==0
- }
- //要排序的区间是array[left,right]
- //1.找基准值
- int originIndex=sanshuQuZhong(array,left,right);
- swap(array,originIndex,right);
- //2.遍历整个区间,把区间分为三部分。 pivotIndex:基准值的下标
- int pivotIndex=parition3(array,left,right);
- //比基准值小的[left,pivotIndex-1]
- //比基准值大的[pivotIndex+1,right]
- //3.分治算法
- //处理比基准值小的区间
- quickSortInner(array,left,pivotIndex-1);
- //处理比基准值大的区间
- quickSortInner(array,pivotIndex+1,right);
- }

时间复杂度 空间复杂度
最好 平均 最坏 最好 平均 最坏
O(nlog(n)) O(nlog(n)) O(n^2) O(logn) O(log(n)) O(n)
不稳定
将待排序的元素序列分成两个长度相等的子序列,对每一个子序列进行排序,然后将它们合并成一个序列。
1)把要排序区间平均切分两部分
2)分治算法,对左右两个区间进行同样方式的排序
直到
size==1 已经有序
size==0 区间没有数了(实际不会走到)
3)合并左右两个有序区间到一个有序区间(需要额外空间)
- public class mergeSort {
- public static void mergeSort(int[] array){
- int[] extra=new int[array.length];
- mergeInner(array,0,array.length,extra);
- }
- //分治算法,对左右两个区间进行同样方式的排序 [low,high)
- private static void mergeInner(int[] array,int low,int high,int[] extra){
- if(low==high-1||low>=high){//如果区间中只有一个数,或没有数,此时有序。则直接返回
- return;
- }
- //计算左右区间 [low,mid) 右:[mid,high)
- int mid=low+(high-low)/2;
- // 分治算法,处理两个小区间
- mergeInner(array,low,mid,extra);
- mergeInner(array,mid,high,extra);
- //两个数组已经有序,下面进行合并两个有序数组
- merge(array,low,mid,high,extra);
- }
- //合并两个有序数组 [low,mid) [mid,high)
- private static void merge(int[] array, int low, int mid,int high, int[] extra) {
- int x=0;
- int i=low;
- int j=mid;
- while(i<mid&&j<high){
- if(array[i]<=array[j]){
- extra[x++]=array[i++];
- }else{
- extra[x++]=array[j++];
- }
- }
- //有一个数组的所有数都被搬完了
- while(i<mid){
- extra[x++]=array[i++];
- }
- while(j<high){
- extra[x++]=array[j++];
- }
- //搬移 extra[0,high-low)-->array[low,high)
- for(int k=low;k<high;k++){
- array[k]=extra[k-low];
- }
- }
-
- public static void main(String[] args) {
- int[] array=new int[]{23,1,45,9,8,5,6,3,10};
- mergeNoR(array);
- for(int item:array){
- System.out.print(item+" ");
- }
- }
- //非递归版本
- public static void mergeNoR(int[] array){
- int[] extra=new int[array.length];
- for(int i=1;i<array.length;i=i*2){
- for(int j=0;j<array.length;j+=2*i){
- int low=j;
- int mid=j+i;
- if(mid>=array.length){
- //越界
- continue;
- }
- int high=mid+i;
- if(high>array.length){
- high=array.length;
- }
- merge(array,low,mid,high,extra);
- }
- }
- }
- }

时间复杂度:O(n*log(n))
空间复杂度:O(n)-->extra[array.length](统一开辟的) 合并n长 log(n)调用栈 "+"的关系
稳定
冒泡排序:优化后的冒泡排序可用于当数据基本有序且数据量较少时。
直接插入排序:在待排序的关键字序列基本有序且数据量较少时。
希尔排序:数据量较小且基本有序时。
选择排序:数据规模较小时。
堆排序:处理数据量大的情况,数据呈流式输入时用堆排序也很方便。
归并排序:数据量较大且要求排序稳定时。
快速排序:处理大量数据时。
稳定算法:冒泡排序、直接插入排序、归并排序。
不稳定算法:希尔排序、简单选择排序、堆排、快排
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。