快速排序

动态图说明

先借用一下wikipedia的一张图 png

快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。

步骤为:

挑选基准值:从数列中挑出一个元素,称为“基准”(pivot), 分割:重新排序数列,所有比基准值小的元素摆放在基准前面,所有比基准值大的元素摆在基准后面(与基准值相等的数可以到任何一边)。在这个分割结束之后,对基准值的排序就已经完成, 递归排序子序列:递归地将小于基准值元素的子序列和大于基准值元素的子序列排序。 递归到最底部的判断条件是数列的大小是零或一,此时该数列显然已经有序。

选取基准值有数种具体方法,此选取方法对排序的时间性能有决定性影响。

Demo说明

举例来说,现有数组 arr = [3,7,8,4,2,1,9,5,5],分区可以分解成以下步骤:

  1. 选择最后一个元素为基准元素:
                               pivot
                                 ↓
    3   7   8   4   2   1   9   5   5
    
  2. 从左到右(除了最后的基准元素),循环移动小于基准元素 5 的所有元素到数组开头,留下大于等于基准元素的元素接在后面。在这个过程它也为基准元素找寻最后摆放的位置。循环流程如下:

循环 i == 0 时,storeIndex == 0,找到一个小于基准元素的元素 3,那么将其与 storeIndex 所在位置的元素交换位置,这里是 3 自身,交换后将 storeIndex 自增 1,storeIndex == 1:

                                pivot
                                  ↓
  3   7   8   4   2   1   9   5   5
  ↑
storeIndex

循环 i == 3 时,storeIndex == 1,找到一个小于基准元素的元素 4:

     ┌───────┐                 pivot
     ↓       ↓                   ↓
 3   7   8   4   2   1   9   5   5
     ↑       ↑
storeIndex   i

交换位置后,storeIndex 自增 1,storeIndex == 2:

                             pivot
                                ↓
3   4   8   7   2   1   9   5   5
        ↑           
   storeIndex

循环 i == 4 时,storeIndex == 2,找到一个小于基准元素的元素 2:

        ┌───────┐             pivot
        ↓       ↓               ↓
3   4   8   7   2   1   9   5   5
        ↑       ↑
   storeIndex   i

交换位置后,storeIndex 自增 1,storeIndex == 3:

                              pivot
                                ↓
3   4   2   7   8   1   9   5   5
            ↑           
       storeIndex

循环 i == 5 时,storeIndex == 3,找到一个小于基准元素的元素 1:

            ┌───────┐         pivot
            ↓       ↓           ↓
3   4   2   7   8   1   9   5   5
            ↑       ↑
       storeIndex   i

交换后位置后,storeIndex 自增 1,storeIndex == 4:

                              pivot
                                ↓
3   4   2   1   8   7   9   5   5
                ↑           
           storeIndex

循环 i == 7 时,storeIndex == 4,找到一个小于等于基准元素的元素 5:

                ┌───────────┐ pivot
                ↓           ↓   ↓
3   4   2   1   8   7   9   5   5
                ↑           ↑
           storeIndex       i

交换后位置后,storeIndex 自增 1,storeIndex == 5:

                              pivot
                                ↓
3   4   2   1   5   7   9   8   5
                    ↑           
               storeIndex

循环结束后交换基准元素和 storeIndex 位置的元素的位置:

                  pivot
                    ↓
3   4   2   1   5   5   9   8   7
                    ↑           
               storeIndex

那么 storeIndex 的值就是基准元素的最终位置,这样整个分区过程就完成了。

接下来就是按照前面的步骤重复拆分[3,4,2,1,5]和[9,8,7]了。