快速排序
快速排序与归并排序一样,都使用了分治思想,即将数据拆分然后进行排序。
快速排序的最佳情况时间复杂度为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 }
浙公网安备 33010602011771号