一 快速排序采用的思想是分治思想:
快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。
private static int nums[];//待排序的数组 public static void QuickSort(int low,int high){ //进行安全性检查 if(low>=high||nums.length<2){ return; } int i = low;//定义左边界 int j = high;//定义右边界 int member = nums[low];//以数组的最左边当做 基准 while(i!=j){ //从右到左进行扫描,寻找比基准member小的元素,并记录于下标j中 while(nums[j]>=member && i<j){ j--; } //从右到左进行扫描,寻找比基准member大的元素,并记录于下标j中 while(nums[i]<=member && i<j){ i++; } //此时 i j 已经定位到相应的元素的下标 if(i<j){ //进行对 i j 下标的元素进行交换 nums[i] += nums[j]; nums[j] = nums[i]- nums[j]; nums[i] = nums[i]- nums[j]; } } //一次划分结束 //当i=j的时候,要把 基准和当前的下标的元素进行交换 //基准,也就是nums[low]里面放的就是基准元素 nums[low] += nums[i];//此时i和j相等 nums[i] = nums[low] - nums[i]; nums[low] = nums[low] - nums[i]; //下面分别对基准的左边和右边进行划分 QuickSort(low,i-1);//对基准的左边进行划分 QuickSort(i+1,high);//对基准的右边进行划确定分 }
快速排序的时间主要耗费在划分操作上,对长度为k的区间进行划分,共需k-1次关键字的比较。
最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n*n)
在最好情况下,每次划分所取的基准都是当前无序区的"中值"记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(nlgn)
尽管快速排序的最坏时间为O(n2),但就平均性能而言,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名。它的平均时间复杂度为O(nlgn)。
这道题你会答吗?花几分钟告诉大家答案吧!
扫描二维码,关注牛客网
下载牛客APP,随时随地刷题
一 快速排序采用的思想是分治思想:
快速排序是找出一个元素(理论上可以随便找一个)作为基准(pivot),然后对数组进行分区操作,使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值,如此作为基准的元素调整到排序后的正确位置。递归快速排序,将其他n-1个元素也调整到排序后的正确位置。最后每个元素都是在排序后的正 确位置,排序完成。所以快速排序算法的核心算法是分区操作,即如何调整基准的位置以及调整返回基准的最终位置以便分治递归。
二 伪代码快速排序的时间主要耗费在划分操作上,对长度为k的区间进行划分,共需k-1次关键字的比较。
最坏情况是每次划分选取的基准都是当前无序区中关键字最小(或最大)的记录,划分的结果是基准左边的子区间为空(或右边的子区间为空),而划分所得的另一个非空的子区间中记录数目,仅仅比划分前的无序区中记录个数减少一个。时间复杂度为O(n*n)
在最好情况下,每次划分所取的基准都是当前无序区的"中值"记录,划分的结果是基准的左、右两个无序子区间的长度大致相等。总的关键字比较次数:O(nlgn)
尽管快速排序的最坏时间为O(n2),但就平均性能而言,它是基于关键字比较的内部排序算法中速度最快者,快速排序亦因此而得名。它的平均时间复杂度为O(nlgn)。