排序算法的c++实现——快速排序
Posted yinheyi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法的c++实现——快速排序相关的知识,希望对你有一定的参考价值。
快速排序是分治思想的又一典型代表,是应用最广的排序算法。分治思想就是把原问题的解分解为两个或多个子问题解,求解出子问题的解之后再构造出原问题的解。
在快速排序算法中,它的思想是把一个待排序的数组分成前半部分和后半部分,并且要求前半部分的值都大于等于或都小于等于后半部分的解, 当前半部分与后半部分都变成有序(通过递归调用快速排序来实现)后,我们就不需要合并两个子问题的解就已经得到了原问题的解。这也是为什么要求前半部分都大于等于或都小于等于后半部分的原因。所以呢,快速排序的核心在于如何把一个待排序的数组分成两部分!
说明几点:
1. 如何把待排序的数组划分为符合要求的两部分!
2. 期望的时间复杂度为O(NlogN), 最坏的时间复杂度为O(N*N)
3. 快速排序为原址排序,不需要额外的内存空间.
4. 快速排序不是稳定排序, 在交换过程中会破坏稳定性。
代码如下:
1 /*********************************************************************** 2 * Copyright (C) 2019 Yinheyi. <[email protected]> 3 * 4 * This program is free software; you can redistribute it and/or modify it under the terms 5 * of the GNU General Public License as published by the Free Software Foundation; either 6 * version 2 of the License, or (at your option) any later version. 7 8 * Brief: 9 * Author: yinheyi 10 * Email: [email protected] 11 * Version: 1.0 12 * Created Time: 2019年05月08日 星期三 21时54分04秒 13 * Modifed Time: 2019年05月10日 星期五 22时16分17秒 14 * Blog: http://www.cnblogs.com/yinheyi 15 * Github: https://github.com/yinheyi 16 * 17 ***********************************************************************/ 18 19 20 // 1. 快速排序是分治思想的又一典型代表,是应用最广的排序算法。 21 // 2. 分治思想就是把原问题的解分解为两个或多个子问题解,求解出子问题的解之后再构造出原 22 // 问题的解。 23 // 3. 在快速排序算法中,它的思想是把一个待排序的数组分成前半部分和后半部分,并且要求 24 // 前半部分的值都大于等于或都小于等于后半部分的解, 当前半部分与后半部分都变成有序(通 25 // 过递归调用快速排序来实现)后,我们就不需要合并两个子问题的解就已经得到了原问题的解。 26 // 这也是为什么要求前半部分都大于等于或都小于等于后半部分的原因。 27 // 4.所以呢,快速排序的核心在于如何把一个待排序的数组分成两部分! 28 // 29 // 核心点: 30 // 1. 如何把待排序的数组划分为符合要求的两部分! 31 // 2. 期望的时间复杂度为O(NlogN), 最坏的时间复杂度为O(N*N) 32 // 3. 快速排序为原址排序,不需要额外的内存空间. 33 // 4. 快速排序不是稳定排序, 在交换过程中会破坏稳定性。 34 // 35 #include<cassert> 36 #include <stdexcept> 37 #include <iostream> 38 static inline void swap(int&, int&); 39 bool less(int lhs, int rhs); 40 bool greate(int lhs, int rhs); 41 static void PrintArray(int array[], int nLength_); 42 typedef bool (*Compare)(int, int); 43 44 /**************** 版本一:使用数组的长度作为参数 ***************/ 45 // 该函数实现对数组数列的划分; 46 // 输入值为数组指针/数组的长度/比较函数指针, 47 // 返回值为划分点的下标, 也就是后半部分第一个元素的下标; 48 int Partition(int array[], int nLength_, Compare CompFunc) 49 { 50 if (array == nullptr || nLength_ <= 0 || CompFunc == nullptr) 51 { 52 assert(false); 53 throw std::invalid_argument("参数不合法!"); 54 } 55 56 int _nBoundValue = array[0]; // 划分区间的边界值 57 int _nBoundIndex = 0; // 指向边界的下标, 即第二部分第一个元素的下标; 58 for (int i = 1; i < nLength_; ++i) 59 { 60 if (CompFunc(array[i], _nBoundValue)) 61 { 62 swap(array[i], array[_nBoundIndex]); 63 ++_nBoundIndex; 64 } 65 } 66 67 // 如果第一个元素正好是最大或最小元素时,把返回值加1, 也就是把数组划分为第一个元素 68 // 和剩余的其它元素两部分。 69 if (0 == _nBoundIndex) 70 return _nBoundIndex + 1; 71 else 72 return _nBoundIndex; 73 } 74 75 // 快速排序的功能函数 76 void QuickSort(int array[], int nLength_, Compare CompFunc) 77 { 78 if (array == nullptr || nLength_ <=1 || CompFunc == nullptr) 79 return; 80 81 int _nPartionIndex = Partition(array, nLength_, CompFunc); 82 QuickSort(array, _nPartionIndex, CompFunc); 83 QuickSort(array + _nPartionIndex, nLength_ - _nPartionIndex, CompFunc); 84 } 85 86 /**************** 版本二:使用数组的下标区间作为参数 ***************/ 87 // 该函数实现对数组的划分。 88 // 输入参数为数组指针/半闭半开区间[start, end)表示的数组范围/比较谓词 89 // 返回值为划分点的下标, 也即后半部分第一个元素的下标。 90 int Partition_Version2(int array[], int nStart_, int nEnd_, Compare CompFunc) 91 { 92 if (array == nullptr || nEnd_ - nStart_ <= 0 || CompFunc == nullptr) 93 { 94 assert(false); 95 throw std::invalid_argument("参数不合法!"); 96 } 97 98 int _nBoundValue = array[nStart_]; // 划分区间的边界值 99 int _nBoundIndex = nStart_; // 指向边界的下标, 即第二部分第一个元素的下标; 100 for (int i = nStart_ + 1; i < nEnd_; ++i) 101 { 102 if (CompFunc(array[i], _nBoundValue)) 103 { 104 swap(array[i], array[_nBoundIndex]); 105 ++_nBoundIndex; 106 } 107 } 108 109 // 如果第一个元素正好是最大或最小元素时,把返回值加1, 也就是把数组划分为第一个元素 110 // 和剩余的其它元素两部分。 111 if (_nBoundIndex == nStart_) 112 return _nBoundIndex + 1; 113 else 114 return _nBoundIndex; 115 } 116 117 void QuickSort_Version2(int array[], int nStart_, int nEnd_, Compare CompFunc) 118 { 119 if (array == nullptr || nEnd_ - nStart_ <= 1 || CompFunc ==nullptr) 120 return; 121 122 int _nPartionIndex = Partition_Version2(array, nStart_, nEnd_, CompFunc); 123 QuickSort_Version2(array, nStart_, _nPartionIndex, CompFunc); 124 QuickSort_Version2(array, _nPartionIndex, nEnd_, CompFunc); 125 } 126 127 // 测试函数 128 /*************** main.c *********************/ 129 int main(int argc, char* argv[]) 130 { 131 int array[10] = {-12, 23, 443, 112, 12, -9098, 3432, 0, 0, 0}; 132 std::cout << "原数组的顺序为:" << std::endl; 133 PrintArray(array, 10); 134 std::cout << "版本一的快速排序:" << std::endl; 135 std::cout << "从小到大:" << std::endl; 136 QuickSort(array, 10, less); 137 PrintArray(array, 10); 138 std::cout << "从大到小:" << std::endl; 139 QuickSort(array, 10, greate); 140 PrintArray(array, 10); 141 std::cout << std::endl; 142 143 144 int array2[10] = {-12, 23, 443, 112, 12, -9098, 3432, 0, 0, 0}; 145 std::cout << "版本二的快速排序:" << std::endl; 146 std::cout << "从小到大:" << std::endl; 147 QuickSort_Version2(array2, 0, 10, less); 148 PrintArray(array2, 10); 149 std::cout << "从大到小:" << std::endl; 150 QuickSort_Version2(array2, 0, 10, greate); 151 PrintArray(array2, 10); 152 153 return 0; 154 } 155 156 157 inline void swap(int& lhs, int& rhs) 158 { 159 int _nTemp = lhs; 160 lhs = rhs; 161 rhs = _nTemp; 162 } 163 164 // 小于比较函数 165 bool less(int lhs, int rhs) 166 { 167 return lhs < rhs; 168 } 169 170 // 大于比较函数 171 bool greate(int lhs, int rhs) 172 { 173 return lhs > rhs; 174 } 175 176 // 打印数组函数 177 static void PrintArray(int array[], int nLength_) 178 { 179 if (nullptr == array || nLength_ <= 0) 180 return; 181 182 for (int i = 0; i < nLength_; ++i) 183 { 184 std::cout << array[i] << " "; 185 } 186 187 std::cout << std::endl; 188 }
以上是关于排序算法的c++实现——快速排序的主要内容,如果未能解决你的问题,请参考以下文章
在最佳情况下,由于堆栈溢出错误,快速排序算法失败 - C++