zoukankan      html  css  js  c++  java
  • 排序算法之快速排序

     今天开始总结排序算法,面试最常考到的应该就是快速排序,也叫做分划交换排序。

           快速排序最明显的特征就是在待排序序列中选择一个分划元素,也叫做主元(pivot),通过一趟排序就会将排序的数据分割成两个部分,主元的左边都比主元小,主元的右边比主元大,再将分成的两边子序列作相同的处理,当所有的子序列为空或者只有一个元素时被认为有序,完成排序。

          网上的快速排序算法一般有两种,一种是两头交换法,另一种是挖坑填坑法。

          我们先来看两头交换法,以{6,5,9,4,2,7,3,}为例,我们一般把左边第一个元素6作为主元,使用两个下标变量i和j分别指向位置一的元素6和和最后位置3,先移动j。i自左往右移动,将主元与下标为i的元素比较,如果主元大于i所指示的元素,则i右移一位 ,直至遇到一个元素不小于主元的停止右移,此时指针i指向9。j自右往左移动,同样遇到一个元素不大于主元时,停止左移此时指针指向3。然后交换i和j所指示的元素,此时序列交换完成为{6,5,3,4,2,7,9}。下一步继续按照同样的方式移动指针i和j,知道i>=j时结束,最后将主元6和位于i的元素交换,结束第一次分划操作。序列为{2,5,3,4,6,7,9}。继续对主元6两边的子序列作相同的处理。

       我们看一下代码。

    public class quickSort {
       public static void quicksort(int arrays[],int left,int right) {
           int x=arrays[left];//主元设为第一个元素
           int i=left;
           int j=right;
           if(left>=right) {
               return; 
           }
           while(i!=j) {
    //移动指针j寻找不大于主元的元素
    while(i<j&&arrays[j]>=x) { j--; } //移动指针i寻找不大于主元的元素 while(i<j&&arrays[i]<=x) { i++; }
    //交换i和j所指示元素
    if(i<j) { int temp=arrays[i]; arrays[i]=arrays[j]; arrays[j]=temp; } }
    //最后将主元和位于i的元素交换,完成一次划分。 arrays[left]
    =arrays[i]; arrays[i]=x; quicksort(arrays,left,i-1); quicksort(arrays,i+1,right); } public static void main(String args[]) { int nums[]= {6,5,9,4,2,7,3}; quicksort(nums,0,6); for(int i=0;i<nums.length-1;i++) { System.out.print(nums[i]+" "); } } }

     第二种挖坑填坑法也不难理解,还是以{6,5,9,4,2,7,3}为例,我们现在以第一个元素为坑也是主元,同样两个指针i和j分别指向6和3,先左移j,找到一个元素不大于主元,此时j指向3,在此位置挖一个坑,把上一个坑用此时j找到的元素填了,此时序列为{3,5,9,4,2,7,3}.然后右移i,直至找到一个元素不小于主元,此时i指向9,在这里挖一个坑,同样用i指向的元素把上一个坑满填上,此时序列为{3,5,9,4,2,7,9}继续重复移动j和i直至i>=j,最后将主元6和位于i的元素交换,结束第一次分划操作。此时序列为{3,5,2,4,6,7,9}。继续对主元6两边的子序列作相同的处理。

    我们看一下代码:

    public class quickSort {
       public static void quicksort(int arrays[],int left,int right) {
           int x=arrays[left];将第一个元素作为主元,同时也是第一个坑
           int i=left;
           int j=right;
           if(left>=right) {
               return; 
           }   
           while(i!=j) {
    // 左移j,找到一个不大于主元的元素
    while(i<j&&arrays[j]>=x) { j--; }
    //用j指向的元素把坑填了,同时在这里挖一个坑。
    if(i<j) { arrays[i]=arrays[j]; }
    //右移i,找到一个元素不小于主元
    while(i<j&&arrays[i]<=x) { i++; }
    //用i指向的元素把坑填了,同时在这里挖一个坑。
    if(i<j) { arrays[j]=arrays[i]; } }
    //最后一个坑用主元填了。 arrays[i]
    =x; quicksort(arrays,left,i-1); quicksort(arrays,i+1,right); } public static void main(String args[]) { int nums[]= {6,5,9,4,2,7,3}; quicksort(nums,0,6); for(int i=0;i<nums.length-1;i++) { System.out.print(nums[i]+" "); } } }

     我们现在看一下快速排序的时间复杂度。如果每次分划操作,左右两个子序列长度基本相等,则效率最高,其最好的时间复杂度为O(nlogn)。反之如果每次分划操作产生的子序列其中一个为空,则快排效率最低,其最坏情况为O(n2),这种情况发生在原始正向有序和反向有序。平均时间复杂度为O(nlogn)。

  • 相关阅读:
    selenium浏览器参数设置详解——转
    py打包工具
    BurpSuite暴力破解和防御实战
    费马小定理(确定n 是否为素数)
    如何实现一个RPC框架1 —— RPC简介和通信协议的定义
    如何实现一个RPC框架2 ——用Netty实现协议通信
    15.三数之和
    flex开发零碎笔记,随时补充
    转“国内图片网站Yupoo的架构”
    转“经验分享:大型高并发高负载网站的系统架构 ”
  • 原文地址:https://www.cnblogs.com/fankailei/p/9769519.html
Copyright © 2011-2022 走看看