快速排序

基本思想

用首元素 x 作划分标准,将输入数组 A划分成不超过 x 的元素构成的数组 AL,大于 x 的元素构成的数组 AR. 其中 AL, AR从左到右存放在数组 A 的位置。递归地对子问题 AL和 AR 进行排序,直到子问题规模为 1 时停止.

划分过程:用首元素作为基准,从后往前找第一个比首元素小的元素,找到后停止,然后从前向后找第一个比首元素大的元素,然后将大元素与小元素做交换,最后返回划分的位置。

时间复杂度分析

  1. 最坏情况下时间复杂度:
    W(n) = W(n-1) + n-1,W(1) = 0,
    则W(n) = n(n-1)/2

  2. 最好划分情况下时间复杂度:
    T(n) = 2T(n/2) + n-1,T(1) = 0
    则T(n) = nlogn

  3. 平均情况时间复杂度: nlogn

    所以最坏情况下时间复杂度:O(n^2),平均情况时间复杂度:nlogn,所以要注意首元素的选取即基准元素的选取

java代码

package com.cn;

import java.util.Arrays;

public class QuickSort
{

    public static void main(String[] args)
    {
        QuickSort qc = new QuickSort();
        int[] arr = { 45, 36, 18, 53, 72, 30, 48, 93, 15, 36 };
        qc.sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public void sort(int[] arr)
    {
        sort(arr, 0, arr.length - 1);
    }

    public void sort(int[] arr, int start, int end)
    {
        if (start < end)
        {
            int location = sortFirstItem(arr, start, end);
            sort(arr, start, location - 1);
            sort(arr, location + 1, end);
        }

    }

    /**
     * 排序第一个元素
     * 
     * @param arr
     * @param start
     * @param end
     * @return 第一个元素排序后的位置
     */
    //以第一个元素为基准,左面的元素小于基准,右面的元素大于基准(划分过程)
    public int sortFirstItem(int[] arr, int start, int end)
    {
        int firstItem = arr[start];
        int first = start + 1, last = end;

        while (first < last)
        {
            //优先找小的元素
            while (firstItem < arr[last] && first < last)
                last--;
            //找大的元素
            while (firstItem >= arr[first] && first < last)
                first++;
            //小元素与大元素做交换
            if (first < last)
            {
                int tmp = arr[first];
                arr[first] = arr[last];
                arr[last] = tmp;

            }
        }

        // 与最后一个最小元素交换
        if (arr[last] < firstItem)
        {
            arr[start] = arr[last];
            arr[last] = firstItem;
            return last;
        }
        // 元素就排在当前位置
        return start;
    }
}

注意:
在划分过程中一定要注意边界问题的处理
如在划分过程中返回值的处理:

  1. 如果先从先往后找第一个比首元素大的元素,再从后往前找第一个比首元素小的元素,则在内部循环结束时,找到的元素是比首元素大的元素,此时如果该元素与首元素交换就会出现问题。
  2. 如果首元素比所有元素都小,first = start+1,last = end,则在从后往前找的过程中就会找到start+1的位置停止,因为此时fist = last,此时序列的划分位置就应该是首元素的位置,所以应该返回start
  3. 还有一种情况就是:如果首元素比所有元素都小,first = start,last = end,在从后往前找时会找到first的位置停止,此时fist = last = start,则返回last就可以了。
    代码如下:
public  int Divide(int[] a,int start,int end){

        int i,j,k,standard;         

         standard = a[start];           

         i = start;
         j = end;        

        while(i<j){         
            while(standard<=a[j]&&i<j)j--;              
            while(standard >= a[i]&&i<j)i++;                    
            if(i<j)
            {
                k=a[i];
                a[i] = a[j];
                a[j] = k;           
            }           
        }

        if(standard < a[i]){
            a[start] = a[i];
            a[i] = standard;
        }
        return i;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值