快速排序是分治思想的又一典型表明,是應用最廣的排序算法。分治思想就是把原問題的解分解爲兩個或多個子問題解,求解出子問題的解以後再構造出原問題的解。ios
在快速排序算法中,它的思想是把一個待排序的數組分紅前半部分和後半部分,而且要求前半部分的值都大於等於或都小於等於後半部分的解, 當前半部分與後半部分都變成有序(經過遞歸調用快速排序來實現)後,咱們就不須要合併兩個子問題的解就已經獲得了原問題的解。這也是爲何要求前半部分都大於等於或都小於等於後半部分的緣由。因此呢,快速排序的核心在於如何把一個待排序的數組分紅兩部分!git
說明幾點:
1. 如何把待排序的數組劃分爲符合要求的兩部分!
2. 指望的時間複雜度爲O(NlogN), 最壞的時間複雜度爲O(N*N)
3. 快速排序爲原址排序,不須要額外的內存空間.
4. 快速排序不是穩定排序, 在交換過程當中會破壞穩定性。
github
代碼以下:redis
1 /*********************************************************************** 2 * Copyright (C) 2019 Yinheyi. <chinayinheyi@163.com> 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: chinayinheyi@163.com 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 }