才辰和小白正在泰山游玩,他们崭新的旅程也从此起航。
才辰:小白,会排序算法吗?
小白:会啊,我可学过很多种排序算法呢。
才辰:是吗,学会哪几种啊?
小白:冒泡排序、插入排序、希尔排序,还有归并排序,嘻嘻。
才辰:不错嘛,那你知道快速排序吗?
小白:快速排序?这个我不知道,很快吗?
才辰:哈哈,快速排序的平均时间复杂度也是O(nlogn).我介绍一下它的思想,你可要认真听哦。
小白:好的,笔记已经拿出来了。
我们从数组中选择一个元素,将此元素作为中轴元素,然后把数组中小于中轴元素的放在其左边,大于中轴元素的放在其右边。此时,中轴元素在数组中已经处于正确的位置。
然后我们把数组分为两部分,中轴元素左边为一部分,右边为一部分,对每一个部分作为一个小的数组,递归的进行如上操作,直到数组的大小为1,此时每个元素都在有序的位置。
才辰:了解了没?
小白:大致了解了,但又不是特别明白。
才辰:正常正常。上面只是大概叙述了一下它的思想,下面我举个例子开详细解释一下哈。
假设有一个数组arr[]={1,3,1,4,5,2,1},对它进行排序,我们每次选取最后一个元素作为中轴元素。
另外,我们定义两个指针i、j,i从左向右移动,j从右向左移动.
开始时,i指向第一个元素,j指向倒数第二个元素。当arr[i]>中轴元素时,停止移动;当arr[j]<中轴元素时,停止移动(i的最大值是arr.length-1,j的最小值是0)。此时判断i与j的大小,如果i
依次对中轴元素左边和右边的数组进行排序。左边的数组只有一个元素1,自然有序;右边的数组同样选取最后一个元素为中轴元素,i指向右边数组的第一个元素,j指向倒数第二个元素。
小白:哦,懂了,这次我大致理解了,那它的时间复杂度是多少呢?
才辰:将数组划分为长度为1的数组需要O(logn),遍历每个数组时间为O(n),所以平均时间复杂度为O(nlogn)。但当数组本身已经有序时,也会退化为O(nn).比如当数组本身已经按从小到大的顺序排好时,划分数组就是O(n)时间了 ,所以总的就是O(nn)。
小白:对对对。
才辰:问个问题,快速排序是稳定排序吗?
小白:不是啊。比如上面的最后一个元素1,排完序之后就在第三个元素1的前面了。
才辰:嗯嗯,对。下面是它的实现代码。
打个光子,大本营在公众号:编程对话。
继续,嘻嘻。
public class Main {
static int partition(int []arr,int left,int right)
{
int i=left-1;//这样写为了下面的++i,方便直接用i
int j=right;
int pivot=arr[right];//选择最后一个元素为基准
while(true)
{
while(arr[++i]<=pivot&&i<right)
;//找到第一个大于pivot的元素
while(arr[--j]>=pivot&&j>0)
;//找到第一个小于pivot的元素
if(i<j)//交换arr[i],arr[j]
{
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
else
break;
}
//交换arr[i]、pivot
int t=arr[i];
arr[i]=arr[right];
arr[right]=t;
return i;
}
public static void quicksort(int []arr,int left,int right)
{
if(left<right)
{
int mid=partition(arr,left,right);//获取中轴元素的位置
quicksort(arr,left,mid-1);//对左边进行排序
quicksort(arr,mid+1,right);//对右边进行排序
}
}
public static void main(String[] args) {
int []arr={1,3,1,4,5,2,1};
int left=0;
int right=arr.length;
quicksort(arr,left,right-1);
for(int i=0;i<right;i++)
{
System.out.print(arr[i]+" ");//输出排序后的数组
}
}
才辰:看懂了吗?
小白:嗯嗯,差不多可以。
才辰:下面我出一个题,你试着自己用快速排序写一下呗。
小白:好的,晚上我试试。
说完之后,才辰、小白又继续欣赏泰山美丽的景色了。
https://leetcode-cn.com/problems/average-salary-excluding-the-minimum-and-maximum-salary/
晚上,小白成功完成了这个题目。
class Solution {
public int partition(int []arr,int left,int right)
{
int i=left-1;
int j=right;
int pivot=arr[right];
while(true)
{
while(arr[++i]<pivot&&i<right)
;
while(arr[--j]>pivot&&j>0)
;
if(i<j)
{
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
else
break;
}
int t=arr[i];
arr[i]=arr[right];
arr[right]=t;
return i;
}
public void quicksort(int []arr,int left,int right)
{
if(left<right)
{
int mid=partition(arr,left,right);
quicksort(arr,left,mid-1);
quicksort(arr,mid+1,right);
}
}
public double average(int[] salary) {
int left=0;
int right=salary.length;
double sum=0;
quicksort(salary,left,right-1);
for(int i=1;i<salary.length-1;i++)
{
sum+=salary[i];
}
return sum/(salary.length-2);
}
}
文:才辰
排版:才辰
公众号:编程对话