对话:快速排序

才辰和小白正在泰山游玩,他们崭新的旅程也从此起航。

才辰:小白,会排序算法吗?

小白:会啊,我可学过很多种排序算法呢。

才辰:是吗,学会哪几种啊?

小白:冒泡排序、插入排序、希尔排序,还有归并排序,嘻嘻。

才辰:不错嘛,那你知道快速排序吗?

小白:快速排序?这个我不知道,很快吗?

才辰:哈哈,快速排序的平均时间复杂度也是O(nlogn).我介绍一下它的思想,你可要认真听哦。

小白:好的,笔记已经拿出来了。

1. 什么是快速排序

我们从数组中选择一个元素,将此元素作为中轴元素,然后把数组中小于中轴元素的放在其左边,大于中轴元素的放在其右边。此时,中轴元素在数组中已经处于正确的位置。

然后我们把数组分为两部分,中轴元素左边为一部分,右边为一部分,对每一个部分作为一个小的数组,递归的进行如上操作,直到数组的大小为1,此时每个元素都在有序的位置。

才辰:了解了没?

小白:大致了解了,但又不是特别明白。

才辰:正常正常。上面只是大概叙述了一下它的思想,下面我举个例子开详细解释一下哈。

2 实例

假设有一个数组arr[]={1,3,1,4,5,2,1},对它进行排序,我们每次选取最后一个元素作为中轴元素。

另外,我们定义两个指针i、j,i从左向右移动,j从右向左移动.

  1. 开始时,i指向第一个元素,j指向倒数第二个元素。当arr[i]>中轴元素时,停止移动;当arr[j]<中轴元素时,停止移动(i的最大值是arr.length-1,j的最小值是0)。此时判断i与j的大小,如果ij时,交换arr[i]与中轴元素的位置,并返回i所指位置;
    对话:快速排序_第1张图片

  2. 依次对中轴元素左边和右边的数组进行排序。左边的数组只有一个元素1,自然有序;右边的数组同样选取最后一个元素为中轴元素,i指向右边数组的第一个元素,j指向倒数第二个元素。
    对话:快速排序_第2张图片

  3. 分别对3左边的元素1、2和右边的元素4、5排序,这样就完成了对整个数组的排序。
    在这里插入图片描述

小白:哦,懂了,这次我大致理解了,那它的时间复杂度是多少呢?

才辰:将数组划分为长度为1的数组需要O(logn),遍历每个数组时间为O(n),所以平均时间复杂度为O(nlogn)。但当数组本身已经有序时,也会退化为O(nn).比如当数组本身已经按从小到大的顺序排好时,划分数组就是O(n)时间了 ,所以总的就是O(nn)。

小白:对对对。

才辰:问个问题,快速排序是稳定排序吗?

小白:不是啊。比如上面的最后一个元素1,排完序之后就在第三个元素1的前面了。

才辰:嗯嗯,对。下面是它的实现代码。

打个光子,大本营在公众号:编程对话。
继续,嘻嘻。

3.实现代码

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]+" ");//输出排序后的数组
       }
}

才辰:看懂了吗?

小白:嗯嗯,差不多可以。

才辰:下面我出一个题,你试着自己用快速排序写一下呗。

小白:好的,晚上我试试。

说完之后,才辰、小白又继续欣赏泰山美丽的景色了。

4 leecode练习题

https://leetcode-cn.com/problems/average-salary-excluding-the-minimum-and-maximum-salary/

对话:快速排序_第3张图片

晚上,小白成功完成了这个题目。

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);
    }
}

                  文:才辰
                排版:才辰
                公众号:编程对话

你可能感兴趣的:(数据结构与算法,排序算法,算法,快速排序,数据结构)