`

快速排序

阅读更多
快速排序
快速排序采用了分治法的思想,把大的问题分解为同类型的小问题。
一般分如下步骤:
1)选择一个中枢元素(有很多选法,我的实现里使用第一个元素为中枢的简单方法)
2)以该中枢元素为基准点,将小于中枢的元素放在中枢后集合的前部分,比它大的在集合后部分,待集合基本排序完成后(此时前部分元素小于后部分元素),把中枢元素放在合适的位置。
3)根据中枢元素最后确定的位置,把数组分成三部分,左边的,右边的,枢纽元素自己,对左边的,右边的分别递归调用快速排序算法即可。

这里的重点与难点在于第二步,实现的方式有很多种,我这里实现了三种。
第一种实现 (partition1方法):
以第一个元素为中枢元素,在中枢元素后面集合中从前往后寻找第一个比中枢元素小的元素,并与第一个元素交换,然后从剩余的元素中寻找第二个比中枢元素小的元素,并与第二位元素交换,这样直到所有小于中枢元素找完为止,并记下最后一次放置小于中枢的元素位置minIndex(即小于中枢与大于中枢的分界),并将中枢元素与minIndex位置元素互换,然后对中枢元素两边的序列进行同样的操作。
此种实现最为简洁,处理过程中不需要把中枢元素移来移去,只是在其它元素完成基本排序后(前部分小于后部分元素)再把中枢元素放置到适当的位置

第二种实现 (partition2方法):
以第一个元素为中枢元素,刚开始时使用低指针指向中枢元素。当中枢元素在低指针位置时,此时我们判断高指针指向的元素是否小于中枢元素,如果大于中枢元素则高指针继续向头移动,如果小于则与中枢元素交换,此时中枢元素被移到了高指针位置;当中枢元素在高指针位置时,我们此时判断低指针指向的元素是否大于中枢元素,如果小于中枢元素则低指针继续向尾移动,如果大于则与中枢元素交换,此时中枢元素又回到了低指针位置;这时是拿高还是低指针所指向的元素与中枢比较时根据前面逻辑来处理,直到高低指针指向同一位置则完成一轮排序,然后再对中枢元素两边的序列进行同样的操作直到排序完成
此种实现逻辑比较好理解,中枢元素的永远在低指针或指针所指向的位置,每次找到需处理的元 素后,要与中枢交换,中枢就像皮球一样从这里踢到那里,又从那里踢到这里。但此种实现会频繁地交换中枢元素,性能可能不如第一种

第三种实现 (partition3方法):
此种方式与前两种方式不太一样,同时移动高低指针,低指针向尾找出大于等于中枢的元素,而高向头找出小于中枢的元素,待两者都找出后交换高低指针所指向的元素,直到高低指针指向同一位置止,然后比较中枢与高低指针所指向的元素大小,如果中枢元素大,则直接与高低指针元素交换,如果中枢元素小于等于高低指针元素,则中枢元素与高低指针前一元素交换,完成一轮比较,然后再对中枢元素两边的序列进行同样的操作直到排序完成

此种方式有点难度,在移动元素时要注意的是:与中枢相等的元素也要向集合后部移动,不然的话如[3,3,0,3,3]第一轮排序结果不准确,虽然最后结果正确。当中枢后面的元素集合移动完成后,还得要把中枢元素放置在集合中的合适位置,这就需要找准集合中前部分与后部分的边界,最后只能把中枢元素与最后一个小于中枢的元素进位置互换。但此种实现方式与第一种有点像,也不需要把中枢元素调来调去的,而是待后面集合排序完成后将中枢放入适当位置


Java代码
package sort;  
 
import java.util.Arrays;  
import java.util.Comparator;  
 
/** 
* 快速排序算法 
* @author jzj 
* @date 2009-12-9 
*  
* @param <E> 
*/ 
public class QuickSort<E extends Comparable<E>> extends Sort<E> {  
 
    /** 
     * 排序算法的实现,对数组中指定的元素进行排序 
     * @param array 待排序的数组 
     * @param from 从哪里开始排序 
     * @param end 排到哪里 
     * @param c 比较器 
     */ 
    public void sort(E[] array, int from, int end, Comparator<E> c) {  
        quickSort(array, from, end, c);  
    }  
 
    /** 
     * 递归快速排序实现 
     * @param array 待排序数组 
     * @param low 低指针 
     * @param high 高指针 
     * @param c 比较器 
     */ 
    private void quickSort(E[] array, int low, int high, Comparator<E> c) {  
        /* 
         * 如果分区中的低指针小于高指针时循环;如果low=higth说明数组只有一个元素,无需再处理; 
         * 如果low > higth,则说明上次枢纽元素的位置pivot就是low或者是higth,此种情况 
         * 下分区不存,也不需处理 
         */ 
        if (low < high) {  
            //对分区进行排序整理  
            int pivot = partition1(array, low, high, c);  
            /* 
             * 以pivot为边界,把数组分成三部分[low, pivot - 1]、[pivot]、[pivot + 1, high] 
             * 其中[pivot]为枢纽元素,不需处理,再对[low, pivot - 1]与[pivot + 1, high] 
             * 各自进行分区排序整理与进一步分区 
             */ 
            quickSort(array, low, pivot - 1, c);  
            quickSort(array, pivot + 1, high, c);  
        }  
 
    }  
 
    /** 
     * 实现一 
     *  
     * @param array 待排序数组 
     * @param low 低指针 
     * @param high 高指针 
     * @param c 比较器 
     * @return int 调整后中枢位置 
     */ 
    private int partition1(E[] array, int low, int high, Comparator<E> c) {  
        E pivotElem = array[low];//以第一个元素为中枢元素  
        //从前向后依次指向比中枢元素小的元素,刚开始时指向中枢,也是小于与大小中枢的元素的分界点  
        int border = low;  
 
        /* 
         * 在中枢元素后面的元素中查找小于中枢元素的所有元素,并依次从第二个位置从前往后存放 
         * 注,这里最好使用i来移动,如果直接移动low的话,最后不知道数组的边界了,但后面需要 
         * 知道数组的边界 
         */ 
        for (int i = low + 1; i <= high; i++) {  
            //如果找到一个比中枢元素小的元素  
            if (c.compare(array[i], pivotElem) < 0) {  
                swap(array, ++border, i);//border前移,表示有小于中枢元素的元素  
            }  
        }  
        /* 
         * 如果border没有移动时说明说明后面的元素都比中枢元素要大,border与low相等,此时是 
         * 同一位置交换,是否交换都没关系;当border移到了high时说明所有元素都小于中枢元素,此 
         * 时将中枢元素与最后一个元素交换即可,即low与high进行交换,大的中枢元素移到了 序列最 
         * 后;如果 low <minIndex< high,表 明中枢后面的元素前部分小于中枢元素,而后部分大于 
         * 中枢元素,此时中枢元素与前部分数组中最后一个小于它的元素交换位置,使得中枢元素放置在 
         * 正确的位置 
         */ 
        swap(array, border, low);  
        return border;  
    }  
 
    /** 
     * 实现二 
     *  
     * @param array 待排序数组 
     * @param low 待排序区低指针 
     * @param high 待排序区高指针 
     * @param c 比较器 
     * @return int 调整后中枢位置 
     */ 
    private int partition2(E[] array, int low, int high, Comparator<E> c) {  
        int pivot = low;//中枢元素位置,我们以第一个元素为中枢元素  
        //退出条件这里只可能是 low = high  
        while (true) {  
            if (pivot != high) {//如果中枢元素在低指针位置时,我们移动高指针  
                //如果高指针元素小于中枢元素时,则与中枢元素交换  
                if (c.compare(array[high], array[pivot]) < 0) {  
                    swap(array, high, pivot);  
                    //交换后中枢元素在高指针位置了  
                    pivot = high;  
                } else {//如果未找到小于中枢元素,则高指针前移继续找  
                    high--;  
                }  
            } else {//否则中枢元素在高指针位置  
                //如果低指针元素大于中枢元素时,则与中枢元素交换  
                if (c.compare(array[low], array[pivot]) > 0) {  
                    swap(array, low, pivot);  
                    //交换后中枢元素在低指针位置了  
                    pivot = low;  
                } else {//如果未找到大于中枢元素,则低指针后移继续找  
                    low++;  
                }  
            }  
            if (low == high) {  
                break;  
            }  
        }  
        //返回中枢元素所在位置,以便下次分区  
        return pivot;  
    }  
 
    /** 
     * 实现三 
     *  
     * @param array 待排序数组 
     * @param low 待排序区低指针 
     * @param high 待排序区高指针 
     * @param c 比较器 
     * @return int 调整后中枢位置 
     */ 
    private int partition3(E[] array, int low, int high, Comparator<E> c) {  
        int pivot = low;//中枢元素位置,我们以第一个元素为中枢元素  
        low++;  
        //----调整高低指针所指向的元素顺序,把小于中枢元素的移到前部分,大于中枢元素的移到后面部分  
        //退出条件这里只可能是 low = high  
 
        while (true) {  
            //如果高指针未超出低指针  
            while (low < high) {  
                //如果低指针指向的元素大于或等于中枢元素时表示找到了,退出,注:等于时也要后移  
                if (c.compare(array[low], array[pivot]) >= 0) {  
                    break;  
                } else {//如果低指针指向的元素小于中枢元素时继续找  
                    low++;  
                }  
            }  
 
            while (high > low) {  
                //如果高指针指向的元素小于中枢元素时表示找到,退出  
                if (c.compare(array[high], array[pivot]) < 0) {  
                    break;  
                } else {//如果高指针指向的元素大于中枢元素时继续找  
                    high--;  
                }  
            }  
            //退出上面循环时 low = high  
            if (low == high) {  
                break;  
            }  
 
            swap(array, low, high);  
        }  
 
        //----高低指针所指向的元素排序完成后,还得要把中枢元素放到适当的位置  
        if (c.compare(array[pivot], array[low]) > 0) {  
            //如果退出循环时中枢元素大于了低指针或高指针元素时,中枢元素需与low元素交换  
            swap(array, low, pivot);  
            pivot = low;  
        } else if (c.compare(array[pivot], array[low]) <= 0) {  
            swap(array, low - 1, pivot);  
            pivot = low - 1;  
        }  
 
        //返回中枢元素所在位置,以便下次分区  
        return pivot;  
    }  
 
    /**  
    * 测试  
    * @param args  
    */ 
    public static void main(String[] args) {  
        Integer[] intgArr = { 3, 1, 1, 1, 1, 1, 1 };  
        QuickSort<Integer> sort = new QuickSort<Integer>();  
        QuickSort.testSort(sort, intgArr);  
        QuickSort.testSort(sort, null);  
    }  
}  
分享到:
评论

相关推荐

    快速排序 快速排序例子

    ### 快速排序知识点解析 #### 一、快速排序简介 快速排序是一种高效的排序算法,由英国计算机科学家托尼·霍尔(Tony Hoare)在1960年提出。它采用分治策略来把一个序列分为较小和较大的两个子序列,然后递归地...

    C语言实现多种链表快速排序

    快速排序是一种高效的排序算法,由英国计算机科学家C.A.R. Hoare在1960年提出,它的基本思想是通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录...

    快速排序 快速排序快速排序快速排序

    快速排序快速排序 快速排序 快速排序 快速排序 快速排序

    确定性快速排序与随机化快速排序的比较

    快速排序是一种高效的排序算法,在计算机科学和数学中被广泛研究。其基本原理是分治法策略,即将一组数据分为两个子序列并分别进行排序。快速排序期望的时间复杂度为O(nlogn),但在最坏的情况下,它的时间复杂度可...

    简单的快速排序

    快速排序是一种高效的排序算法,由英国计算机科学家C.A.R. Hoare在1960年提出。它的基本思想是分治法(Divide and Conquer),即把一个大问题分解成若干个小问题来解决,最终将小问题的结果合并得到原问题的解。在这...

    排序算法编程 堆排序 快速排序

    本主题将深入探讨四种常见的排序算法:堆排序、快速排序以及两种未在标题中明确提到但同样重要的排序方法——基数排序和计数排序。 首先,让我们详细了解一下堆排序。堆排序是一种基于比较的排序算法,利用了数据...

    全版快速排序推荐PPT.ppt

    根据提供的文件信息,我们可以深入探讨快速排序这一算法的相关知识点,包括其原理、编程思路、涉及的知识点以及具体的实现方式。 ### 快速排序原理 快速排序是一种高效的排序算法,属于**分而治之**策略的一种典型...

    快速排序的并行算法

    ### 快速排序的并行算法 #### 快速排序基础概念 快速排序是一种非常高效的排序算法,由C.A.R. Hoare在1962年提出。它采用分治法的思想来对数组进行排序。具体操作是选择一个元素作为基准(pivot),然后通过一趟...

    快速排序 --- 非递归实现

    快速排序是一种高效的排序算法,由英国计算机科学家C.A.R. Hoare在1960年提出。它的基本思想是分治法,通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再按...

    快速排序算法(c#实现)

    快速排序是一种高效的排序算法,由英国计算机科学家C.A.R. Hoare在1960年提出。它的基本思想是分治策略,通过一趟排序将待排序的数据分割成独立的两部分,其中一部分的所有数据都比另一部分的所有数据都要小,然后再...

    快速排序算法相关分析

    快速排序算法是一种有效的排序算法,虽然算法在最坏的情况下运行时间为 O(n^2),但由于平均运行时间为 O(nlogn),并且在内存使用、程序实现复杂性上表现优秀,尤其是对快速排序算法进行随机化的可能,使得快速排序在...

    随机快速排序 算法设计与分析实验报告

    (1)用随机快速排序的方法,对输入的数值以从大到小的顺序进行快速排序。 (2)对随机快速排序和冒泡排序这两种排序方法进行比较,测试其在不同数值大小的情况下算法运行的时间复杂度。 二、 实验要求 快速排序...

    快速排序算法的java实现

    快速排序是一种高效的排序算法,由英国计算机科学家C.A.R. Hoare在1960年提出。它的基本思想是分治法(Divide and Conquer),通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的...

    冒泡排序和快速排序的时间性能

    冒泡排序和快速排序的时间性能 冒泡排序和快速排序是两种常用的排序算法,它们的时间性能是开发者和研究人员所关心的热点话题。在本文中,我们将对冒泡排序和快速排序的时间性能进行深入分析和比较。 冒泡排序是一...

    快速排序的递归简洁实现

    快速排序是一种高效的排序算法,由英国计算机科学家托尼·霍尔于1960年提出。它采用分治策略来把一个序列分为较小的两个子序列,然后递归地对子序列进行排序,最终合并得到有序序列。快速排序在平均情况下的时间...

    TIA博途中通过SCL语言实现快速排序的具体方法示例.docx

    快速排序是一种高效的排序算法,由英国计算机科学家C.A.R. Hoare在1960年提出。它基于分治法的策略,通过选取一个基准值并重新排列数组,将问题分解为较小的部分,然后递归地对这些部分进行排序,最终达到整个序列...

    快速排序演示程序/vc++/mfc

    快速排序是一种高效的排序算法,由英国计算机科学家C.A.R. Hoare在1960年提出。它基于分治策略,通常比其他O(n^2)时间复杂度的排序算法更快,平均时间复杂度为O(n log n)。在本项目中,“快速排序演示程序/vc++/mfc...

    《快速排序 直接插入排序 堆排序 希尔排序 选择排序:五种排序》

    (1) 完成5种常用内部排序算法的演示,5种排序算法为:快速排序,直接插入排序,选择排序,堆排序,希尔排序; (2) 待排序元素为整数,排序序列存储在数据文件中,要求排序元素不少于30个; (3) 演示程序开始,...

    FPGA并行快速排序算法-位宽可设

    在本文中,我们将深入探讨基于FPGA的并行快速排序算法,特别关注“位宽可设”的特性。这种算法能够高效地处理大量数据,并且在硬件实现上具有很高的灵活性。我们将从以下几个方面来阐述这个主题: 一、快速排序算法...

    数据结构 快速排序 输出每一趟结果

    根据给定文件的信息,我们可以总结出以下关于“数据结构 快速排序 输出每一趟结果”的知识点: ### 一、快速排序的基本概念 快速排序是一种高效的排序算法,采用分治法策略来把一个序列分为较小和较大的两个子序列...

Global site tag (gtag.js) - Google Analytics