排序算法的c++實現——快速排序


    快速排序是分治思想的又一典型代表,是應用最廣的排序算法。分治思想就是把原問題的解分解為兩個或多個子問題解,求解出子問題的解之后再構造出原問題的解。

    在快速排序算法中,它的思想是把一個待排序的數組分成前半部分和后半部分,並且要求前半部分的值都大於等於或都小於等於后半部分的解, 當前半部分與后半部分都變成有序(通過遞歸調用快速排序來實現)后,我們就不需要合並兩個子問題的解就已經得到了原問題的解。這也是為什么要求前半部分都大於等於或都小於等於后半部分的原因。所以呢,快速排序的核心在於如何把一個待排序的數組分成兩部分!


說明幾點:
1. 如何把待排序的數組划分為符合要求的兩部分!
2. 期望的時間復雜度為O(NlogN), 最壞的時間復雜度為O(N*N)
 3. 快速排序為原址排序,不需要額外的內存空間.
 4. 快速排序不是穩定排序, 在交換過程中會破壞穩定性。

代碼如下:

  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   }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM