从快速排序开始的代码演化
note: 本文不讨论快速排序的优化。
最近在温习算法。正好看到快速排序。
通过3个版本的改进,慢慢加入了template技能。这应该也算是一个收获。
第一个版本:测试正确性。
通过比较int的数组排序。
1 int doSort(int* collection, int left, int right) 2 { 3 int newRight; 4 5 if (left < right) 6 { 7 newRight = doPartition(collection, left, right); 8 doSort(collection, left, newRight); 9 doSort(collection, newRight + 1, right); 10 } 11 return 0; 12 } 13 14 bool FindMidValue( int& exA, int& exB, int& exC,int& result) 15 { 16 if(exA>exB) 17 { 18 if(exB>exC) 19 { 20 result = exB; 21 return true; 22 } 23 if(exA>exC) 24 { 25 result = exC; 26 return true; 27 } 28 result = exA; 29 return true; 30 } 31 return false; 32 33 } 34 35 36 37 void doQueryMidValue(int* collection,int example1,int example2,int example3,int& result) 38 { 39 int& exA = collection[example1]; 40 int& exB = collection[example2]; 41 int& exC = collection[example3]; 42 43 if(FindMidValue(exA,exB,exC,result)) return; 44 if(FindMidValue(exA,exC,exB,result)) return; 45 if(FindMidValue(exB,exA,exC,result)) return; 46 if(FindMidValue(exB,exC,exA,result)) return; 47 if(FindMidValue(exC,exA,exB,result)) return; 48 if(FindMidValue(exC,exB,exA,result)) return; 49 result = exA; 50 } 51 52 53 int doPartition(int* collection,int left, int right) 54 { 55 int cmpValue ; 56 int example1 = (rand() % (right - left + 1)) + left; 57 int example2 =(rand() % (right - left + 1)) + left; 58 int example3 = (rand() % (right - left + 1)) + left; 59 doQueryMidValue(collection,example1,example2,example3,cmpValue); 60 61 left--; 62 right++; 63 while (1) 64 { 65 do 66 { 67 right--; 68 } while (collection[right] > cmpValue); 69 70 do 71 { 72 left++; 73 }while (collection[left] < cmpValue); 74 75 if (left >= right) 76 { 77 break; 78 } 79 else 80 { 81 int nTemp = collection[left]; 82 collection[left] = collection[right]; 83 collection[right] = nTemp; 84 } 85 } 86 return right; 87 }
第二个版本:支持泛型。
如果我要支持string,不能再写一个版本,所以第二版解决数据类型变化的问题。
同时使用vector代替原始数组。
1 #include "stdafx.h" 2 #include <xstddef> 3 #include <algorithm> 4 #include <vector> 5 #include <stdlib.h> 6 7 namespace BSP 8 { 9 template<class T> 10 class QuickSort 11 { 12 13 14 public: 15 int Sort(std::vector< T >& collection); 16 private: 17 int doSort(std::vector< T >& collection,int left, int right); 18 int doPartition(std::vector< T >& collection,int left, int right); 19 void doQueryMidValue(std::vector< T >& collection,int example1,int example2,int example3,T& result); 20 bool FindMidValue( T& exA, T& exB, T& exC,T& result); 21 }; 22 23 24 template<class T> 25 int QuickSort<T>::Sort(std::vector<T>& collection) 26 { 27 return doSort(collection,0,collection.size()-1); 28 } 29 30 template<class T> 31 int QuickSort<T>::doSort(std::vector<T>& collection,int left, int right) 32 { 33 int newRight; 34 35 if (left < right) 36 { 37 newRight = doPartition(collection, left, right); 38 doSort(collection, left, newRight); 39 doSort(collection, newRight + 1, right); 40 } 41 return 0; 42 } 43 44 template<class T> 45 bool QuickSort<T>::FindMidValue( T& exA, T& exB, T& exC,T& result) 46 { 47 if(exA>exB) 48 { 49 if(exB>exC) 50 { 51 result = exB; 52 return true; 53 } 54 if(exA>exC) 55 { 56 result = exC; 57 return true; 58 } 59 result = exA; 60 return true; 61 } 62 return false; 63 64 } 65 66 template<class T> 67 void QuickSort<T>::doQueryMidValue(std::vector< T >& collection,int example1,int example2,int example3,T& result) 68 { 69 T& exA = collection[example1]; 70 T& exB = collection[example2]; 71 T& exC = collection[example3]; 72 73 if(FindMidValue(exA,exB,exC,result)) return; 74 if(FindMidValue(exA,exC,exB,result)) return; 75 if(FindMidValue(exB,exA,exC,result)) return; 76 if(FindMidValue(exB,exC,exA,result)) return; 77 if(FindMidValue(exC,exA,exB,result)) return; 78 if(FindMidValue(exC,exB,exA,result)) return; 79 result = exA; 80 } 81 82 template<class T> 83 int QuickSort<T>::doPartition(std::vector<T>& collection,int left, int right) 84 { 85 T cmpValue ; 86 int example1 = (rand() % (right - left + 1)) + left; 87 int example2 =(rand() % (right - left + 1)) + left; 88 int example3 = (rand() % (right - left + 1)) + left; 89 doQueryMidValue(collection,example1,example2,example3,cmpValue); 90 91 left--; 92 right++; 93 while (1) 94 { 95 do 96 { 97 right--; 98 } while (m_pfnGreater(collection[right] , cmpValue)); 99 100 do 101 { 102 left++; 103 }while (m_pfnLess(collection[left] , cmpValue)); 104 105 if (left >= right) 106 { 107 break; 108 } 109 else 110 { 111 std::swap(collection[left],collection[right]); 112 } 113 } 114 return right; 115 } 116 }
第二个版本b:支持自定义的结构。
基础类型int,stl的类型string都内建比较函数。所以可以直接比较。
但自定义的类型,编译器就无法识别了。
第二个版本不动,自定义的结构需要重载operator 。
1 typedef struct Student 2 { 3 std::string name; 4 int year; 5 6 bool operator > (const struct Student& dst) const 7 { 8 printf("ref greater \n"); 9 return this->year > dst.year; 10 } 11 12 bool operator < (const struct Student& dst) const 13 { 14 printf("ref less \n"); 15 return this->year < dst.year; 16 } 17 } Student;
第三个版本:支持shared_Ptr。
之前的版本需要存放实体,这个对于性能有很大影响。
于是引入了shared_ptr。但这时比较函数进行的是shared_ptr的比较,并不是实际对象的比较。
所以需要增加自定义的比较函数。
首先需要提供默认的比较函数对象。这样默认类型就不用强制设置了。
1 template<class T 2 ,class _qsLess = std::less<T>,class _qsGreater = std::greater<T>> 3 4 class QuickSort 5 { 6 public: 7 explicit QuickSort<T,_qsLess,_qsGreater>() 8 { 9 m_pfnLess = _qsLess(); 10 m_pfnGreater = _qsGreater(); 11 } 12 public: 13 int Sort(std::vector< T >& collection); 14 private: 15 int doSort(std::vector< T >& collection,int left, int right); 16 int doPartition(std::vector< T >& collection,int left, int right); 17 void doQueryMidValue(std::vector< T >& collection,int example1,int example2,int example3,T& result); 18 bool FindMidValue( T& exA, T& exB, T& exC,T& result); 19 private: 20 _qsLess m_pfnLess; 21 _qsGreater m_pfnGreater; 22 }; 23 24 25 template<class T,class _qsLess ,class _qsGreater> 26 int QuickSort<T,_qsLess,_qsGreater>::Sort(std::vector<T>& collection) 27 { 28 return doSort(collection,0,collection.size()-1); 29 } 30 31 template<class T,class _qsLess ,class _qsGreater> 32 int QuickSort<T,_qsLess,_qsGreater>::doSort(std::vector<T>& collection,int left, int right) 33 { 34 int newRight; 35 36 if (left < right) 37 { 38 newRight = doPartition(collection, left, right); 39 doSort(collection, left, newRight); 40 doSort(collection, newRight + 1, right); 41 } 42 return 0; 43 } 44 45 template<class T,class _qsLess ,class _qsGreater> 46 bool QuickSort<T,_qsLess,_qsGreater>::FindMidValue( T& exA, T& exB, T& exC,T& result) 47 { 48 if(m_pfnGreater(exA,exB)) 49 { 50 if(m_pfnGreater(exB,exC)) 51 { 52 result = exB; 53 return true; 54 } 55 if(m_pfnGreater(exA,exC)) 56 { 57 result = exC; 58 return true; 59 } 60 result = exA; 61 return true; 62 } 63 return false; 64 65 } 66 67 template<class T,class _qsLess ,class _qsGreater> 68 void QuickSort<T,_qsLess,_qsGreater>::doQueryMidValue(std::vector< T >& collection,int example1,int example2,int example3,T& result) 69 { 70 T& exA = collection[example1]; 71 T& exB = collection[example2]; 72 T& exC = collection[example3]; 73 74 if(FindMidValue(exA,exB,exC,result)) return; 75 if(FindMidValue(exA,exC,exB,result)) return; 76 if(FindMidValue(exB,exA,exC,result)) return; 77 if(FindMidValue(exB,exC,exA,result)) return; 78 if(FindMidValue(exC,exA,exB,result)) return; 79 if(FindMidValue(exC,exB,exA,result)) return; 80 result = exA; 81 } 82 83 template<class T,class _qsLess ,class _qsGreater> 84 int QuickSort<T,_qsLess,_qsGreater>::doPartition(std::vector<T>& collection,int left, int right) 85 { 86 T cmpValue ; 87 int example1 = (rand() % (right - left + 1)) + left; 88 int example2 =(rand() % (right - left + 1)) + left; 89 int example3 = (rand() % (right - left + 1)) + left; 90 doQueryMidValue(collection,example1,example2,example3,cmpValue); 91 92 left--; 93 right++; 94 while (1) 95 { 96 do 97 { 98 right--; 99 }while (m_pfnGreater(collection[right] , cmpValue)); 100 do 101 { 102 left++; 103 }while (m_pfnLess(collection[left] , cmpValue)); 104 if (left >= right) 105 { 106 break; 107 } 108 else 109 { 110 std::swap(collection[left],collection[right]); 111 } 112 } 113 return right; 114 }
对于使用者,需要增加比较函数的实现。
1 struct StudentPtrLess:public std::binary_function<StudentPtr, StudentPtr, bool> 2 { 3 bool operator () ( StudentPtr& src, StudentPtr& dst) 4 { 5 if(src == false) return true; 6 if(dst == false) return false; 7 return *(src.get()) < *(dst.get()); 8 } 9 }; 10 11 struct StudentPtrGreater:public std::binary_function<StudentPtr, StudentPtr, bool> 12 { 13 bool operator () ( StudentPtr& src, StudentPtr& dst) 14 { 15 if(src == false) return false; 16 if(dst == false) return true; 17 return *(src.get()) > *(dst.get()); 18 } 19 }; 20 21 BSP::QuickSort< StudentPtr ,StudentPtrLess , StudentPtrGreater> qsStudentPtr;