快速排序

  快速排序与归并排序一样,都使用了分治思想,即将数据拆分然后进行排序。

  快速排序的最佳情况时间复杂度为O(NlogN),最糟复杂度则为O(N^2),但是它的平均性能是最佳的,并且快速排序的一个优势就是快速排序可以在数据本身进行排序,不需要开辟额外的内存空间(归并排序需要提前开辟一块O(N)的内存空间用以存储过程中拼接出来的数组),所以快排的运用范围十分广泛。

  快排的主要思想步骤就是:

    1.先在数据中选出一个基准值Key(可以是首尾元素,也可以是中间元素)

    2.遍历除Key以外的元素,比Key大放在Key右侧,比Key小放在Key左侧

    3.根据Key进行拆分,递归排序左起点至Key-1和Key+1至右终点

  

  

  上图的r就是基准值Key的索引,p为大值(比Key大的元素)的起始索引值,i则为小值的末尾索引值

  初始化的时候,因为还没有开始,所以默认没有存在比Key小的元素,所以i要在左起始值的左侧,不在范围内。遍历则由p从左起始位置开始,如果碰见比Key小的,便让i进位(相当于小值范围+1),然后交换i与p的元素,依次类推,直至p完成了r前一个元素的排序。

  一切完毕后,因为i为小值最后一位,所以i+1则为大值第一位。将大值第一位和r交换,便可确保r左侧都是小值,r右侧都是大值。

  这部分内容为划分部分,下面是C++代码(i为left,p为循环中的i,r为keyIndex):

 

 1 /// <summary>
 2 /// 划分数据,同时得出基准值
 3 /// </summary>
 4 /// <param name="nums">需要排序的数据</param>
 5 /// <param name="start">起点</param>
 6 /// <param name="keyIndex">终点</param>
 7 /// <returns>基准值的索引</returns>
 8 int partition(vector<int>& nums, int start, int keyIndex) {
 9     int key = nums[keyIndex];                    //默认将最后一个元素作为基准值
10     int left = start - 1;                        //left为比key小的元素范围终点,一开始不存在,所以不在范围里
11     //从起点开始遍历,如果找到比key小的,left进位然后与nums[keyIndex]交换
12     //即将比key小的元素都放在left前面,left为小元素的最后一个元素索引值
13     for (int i = start; i < keyIndex; i++) {
14         if (nums[i] <= key) {
15             left += 1;
16             int temp = nums[i];
17             nums[i] = nums[left];
18             nums[left] = temp;
19         }
20     }
21     int temp = nums[left + 1];                    //因为left为小值最后一位,所以left + 1为大值第一位
22     nums[left + 1] = nums[keyIndex];            //将大值第一位和key交换一下位置
23     nums[keyIndex] = temp;
24 
25     return left + 1;
26 }

  然后就是主体框架,先划分得到基准值,然后对着基准值两边继续排序:

 1 /// <summary>
 2 /// 快速排序
 3 /// </summary>
 4 /// <param name="nums">需要排序的数据</param>
 5 /// <param name="left">起点</param>
 6 /// <param name="right">终点</param>
 7 void quickSortStep(vector<int>& nums, int left, int right) {
 8     if (left < right) {
 9         int keyIndex = partition(nums, left, right);
10         quickSortStep(nums, left, keyIndex - 1);
11         quickSortStep(nums, keyIndex + 1, right);
12     }
13 }

  

  将这些代码整合到一起,就是最终的快速排序,下面是全部代码:

 1 void quickSort(vector<int>& nums) {
 2     if (nums.size() <= 1) {
 3         return;
 4     }
 5     quickSortStep(nums, 0, nums.size() - 1);
 6 }
 7 
 8 /// <summary>
 9 /// 快速排序
10 /// </summary>
11 /// <param name="nums">需要排序的数据</param>
12 /// <param name="left">起点</param>
13 /// <param name="right">终点</param>
14 void quickSortStep(vector<int>& nums, int left, int right) {
15     if (left < right) {
16         int keyIndex = partition(nums, left, right);
17         quickSortStep(nums, left, keyIndex - 1);
18         quickSortStep(nums, keyIndex + 1, right);
19     }
20 }
21 
22 /// <summary>
23 /// 划分数据,同时得出基准值
24 /// </summary>
25 /// <param name="nums">需要排序的数据</param>
26 /// <param name="start">起点</param>
27 /// <param name="keyIndex">终点</param>
28 /// <returns>基准值的索引</returns>
29 int partition(vector<int>& nums, int start, int keyIndex) {
30     int key = nums[keyIndex];                    //默认将最后一个元素作为基准值
31     int left = start - 1;                        //left为比key小的元素范围终点,一开始不存在,所以不在范围里
32     //从起点开始遍历,如果找到比key小的,left进位然后与nums[keyIndex]交换
33     //即将比key小的元素都放在left前面,left为小元素的最后一个元素索引值
34     for (int i = start; i < keyIndex; i++) {
35         if (nums[i] <= key) {
36             left += 1;
37             int temp = nums[i];
38             nums[i] = nums[left];
39             nums[left] = temp;
40         }
41     }
42     int temp = nums[left + 1];                    //因为left为小值最后一位,所以left + 1为大值第一位
43     nums[left + 1] = nums[keyIndex];            //将大值第一位和key交换一下位置
44     nums[keyIndex] = temp;
45 
46     return left + 1;
47 }

 

posted @ 2021-09-23 15:44  可乐社区  阅读(90)  评论(0)    收藏  举报