標籤:
note: 本文不討論快速排序的最佳化。
最近在溫習演算法。正好看到快速排序。
通過3個版本的改進,慢慢加入了template技能。這應該也算是一個收穫。
第一個版本:測試正確性。
通過比較int的數組排序。
int doSort(int* collection, int left, int right){ int newRight; if (left < right) { newRight = doPartition(collection, left, right); doSort(collection, left, newRight); doSort(collection, newRight + 1, right); } return 0;}bool FindMidValue( int& exA, int& exB, int& exC,int& result){ if(exA>exB) { if(exB>exC) { result = exB; return true; } if(exA>exC) { result = exC; return true; } result = exA; return true; } return false;}void doQueryMidValue(int* collection,int example1,int example2,int example3,int& result){ int& exA = collection[example1]; int& exB = collection[example2]; int& exC = collection[example3]; if(FindMidValue(exA,exB,exC,result)) return; if(FindMidValue(exA,exC,exB,result)) return; if(FindMidValue(exB,exA,exC,result)) return; if(FindMidValue(exB,exC,exA,result)) return; if(FindMidValue(exC,exA,exB,result)) return; if(FindMidValue(exC,exB,exA,result)) return; result = exA;}int doPartition(int* collection,int left, int right) { int cmpValue ; int example1 = (rand() % (right - left + 1)) + left; int example2 =(rand() % (right - left + 1)) + left; int example3 = (rand() % (right - left + 1)) + left; doQueryMidValue(collection,example1,example2,example3,cmpValue); left--; right++; while (1) { do { right--; } while (collection[right] > cmpValue); do { left++; }while (collection[left] < cmpValue); if (left >= right) { break; } else { int nTemp = collection[left]; collection[left] = collection[right]; collection[right] = nTemp; } } return right;}
第二個版本:支援泛型。
如果我要支援string,不能再寫一個版本,所以第二版解決資料類型變化的問題。
同時使用vector代替原始數組。
#include "stdafx.h"#include <xstddef>#include <algorithm>#include <vector>#include <stdlib.h>namespace BSP{ template<class T> class QuickSort { public: int Sort(std::vector< T >& collection); private: int doSort(std::vector< T >& collection,int left, int right); int doPartition(std::vector< T >& collection,int left, int right); void doQueryMidValue(std::vector< T >& collection,int example1,int example2,int example3,T& result); bool FindMidValue( T& exA, T& exB, T& exC,T& result); }; template<class T> int QuickSort<T>::Sort(std::vector<T>& collection) { return doSort(collection,0,collection.size()-1); } template<class T> int QuickSort<T>::doSort(std::vector<T>& collection,int left, int right) { int newRight; if (left < right) { newRight = doPartition(collection, left, right); doSort(collection, left, newRight); doSort(collection, newRight + 1, right); } return 0; } template<class T> bool QuickSort<T>::FindMidValue( T& exA, T& exB, T& exC,T& result) { if(exA>exB) { if(exB>exC) { result = exB; return true; } if(exA>exC) { result = exC; return true; } result = exA; return true; } return false; } template<class T> void QuickSort<T>::doQueryMidValue(std::vector< T >& collection,int example1,int example2,int example3,T& result) { T& exA = collection[example1]; T& exB = collection[example2]; T& exC = collection[example3]; if(FindMidValue(exA,exB,exC,result)) return; if(FindMidValue(exA,exC,exB,result)) return; if(FindMidValue(exB,exA,exC,result)) return; if(FindMidValue(exB,exC,exA,result)) return; if(FindMidValue(exC,exA,exB,result)) return; if(FindMidValue(exC,exB,exA,result)) return; result = exA; } template<class T> int QuickSort<T>::doPartition(std::vector<T>& collection,int left, int right) { T cmpValue ; int example1 = (rand() % (right - left + 1)) + left; int example2 =(rand() % (right - left + 1)) + left; int example3 = (rand() % (right - left + 1)) + left; doQueryMidValue(collection,example1,example2,example3,cmpValue); left--; right++; while (1) { do { right--; } while (m_pfnGreater(collection[right] , cmpValue)); do { left++; }while (m_pfnLess(collection[left] , cmpValue)); if (left >= right) { break; } else { std::swap(collection[left],collection[right]); } } return right; }}
第二個版本b:支援自訂的結構。
基礎類型int,stl的類型string都內建比較函數。所以可以直接比較。
但自訂的類型,編譯器就無法識別了。
第二個版本不動,自訂的結構需要重載operator 。
typedef struct Student{ std::string name; int year; bool operator > (const struct Student& dst) const { printf("ref greater \n"); return this->year > dst.year; } bool operator < (const struct Student& dst) const { printf("ref less \n"); return this->year < dst.year; }} Student;
第三個版本:支援shared_Ptr。
之前的版本需要存放實體,這個對於效能有很大影響。
於是引入了shared_ptr。但這時比較函數進行的是shared_ptr的比較,並不是實際對象的比較。
所以需要增加自訂的比較函數。
首先需要提供預設的比較函數對象。這樣預設類型就不用強制設定了。
template<class T ,class _qsLess = std::less<T>
,class _qsGreater = std::greater<T>
> class QuickSort { public: explicit QuickSort<T,_qsLess,_qsGreater>() { m_pfnLess = _qsLess(); m_pfnGreater = _qsGreater(); } public: int Sort(std::vector< T >& collection); private: int doSort(std::vector< T >& collection,int left, int right); int doPartition(std::vector< T >& collection,int left, int right); void doQueryMidValue(std::vector< T >& collection,int example1,int example2,int example3,T& result); bool FindMidValue( T& exA, T& exB, T& exC,T& result); private: _qsLess m_pfnLess; _qsGreater m_pfnGreater; }; template<class T,class _qsLess ,class _qsGreater> int QuickSort<T,_qsLess,_qsGreater>::Sort(std::vector<T>& collection) { return doSort(collection,0,collection.size()-1); } template<class T,class _qsLess ,class _qsGreater> int QuickSort<T,_qsLess,_qsGreater>::doSort(std::vector<T>& collection,int left, int right) { int newRight; if (left < right) { newRight = doPartition(collection, left, right); doSort(collection, left, newRight); doSort(collection, newRight + 1, right); } return 0; } template<class T,class _qsLess ,class _qsGreater> bool QuickSort<T,_qsLess,_qsGreater>::FindMidValue( T& exA, T& exB, T& exC,T& result) { if(m_pfnGreater(exA,exB)) { if(m_pfnGreater(exB,exC)) { result = exB; return true; } if(m_pfnGreater(exA,exC)) { result = exC; return true; } result = exA; return true; } return false; } template<class T,class _qsLess ,class _qsGreater> void QuickSort<T,_qsLess,_qsGreater>::doQueryMidValue(std::vector< T >& collection,int example1,int example2,int example3,T& result) { T& exA = collection[example1]; T& exB = collection[example2]; T& exC = collection[example3]; if(FindMidValue(exA,exB,exC,result)) return; if(FindMidValue(exA,exC,exB,result)) return; if(FindMidValue(exB,exA,exC,result)) return; if(FindMidValue(exB,exC,exA,result)) return; if(FindMidValue(exC,exA,exB,result)) return; if(FindMidValue(exC,exB,exA,result)) return; result = exA; } template<class T,class _qsLess ,class _qsGreater> int QuickSort<T,_qsLess,_qsGreater>::doPartition(std::vector<T>& collection,int left, int right) { T cmpValue ; int example1 = (rand() % (right - left + 1)) + left; int example2 =(rand() % (right - left + 1)) + left; int example3 = (rand() % (right - left + 1)) + left; doQueryMidValue(collection,example1,example2,example3,cmpValue); left--; right++; while (1) { do { right--; }while (m_pfnGreater(collection[right] , cmpValue));
do { left++; }while (m_pfnLess(collection[left] , cmpValue));
if (left >= right) { break; } else { std::swap(collection[left],collection[right]); } } return right; }
對於使用者,需要增加比較函數的實現。
struct StudentPtrLess:public std::binary_function<StudentPtr, StudentPtr, bool> { bool operator () ( StudentPtr& src, StudentPtr& dst) { if(src == false) return true; if(dst == false) return false; return *(src.get()) < *(dst.get()); } }; struct StudentPtrGreater:public std::binary_function<StudentPtr, StudentPtr, bool> { bool operator () ( StudentPtr& src, StudentPtr& dst) { if(src == false) return false; if(dst == false) return true; return *(src.get()) > *(dst.get()); } }; BSP::QuickSort< StudentPtr ,StudentPtrLess , StudentPtrGreater> qsStudentPtr;
從快速排序開始的代碼演化