因為 sort 太經典了,今天就來實作一下經典的排序演算法:
就用 Leetcode # 912 - Sort an Array 當作測試介面。
Quicksort
Merge Sort
先自己憑著對演算法的印象,實作了一版爛爛的 Merge Sort:
Copy class Solution {
public :
vector < int > sortArray ( vector < int > & nums) {
mergeSort (nums , 0 , nums . size () - 1 );
return nums;
}
private :
void mergeSort ( vector < int > & nums , int start , int end) {
if (start == end)
return ;
int mid = start + (end - start) / 2 ;
mergeSort (nums , start , mid);
mergeSort (nums , mid + 1 , end);
merge (nums , start , mid , mid + 1 , end);
}
void merge ( vector < int > & nums , int l_start , int l_end , int r_start , int r_end) {
int l = l_start , r = r_start , cur = l_start;
vector <int> ans = nums;
while (l <= l_end && r <= r_end) {
if ( nums [l] <= nums [r])
ans [cur ++ ] = nums [l ++ ];
else
ans [cur ++ ] = nums [r ++ ];
}
while (l <= l_end)
ans [cur ++ ] = nums [l ++ ];
while (r <= r_end)
ans [cur ++ ] = nums [r ++ ];
nums = ans;
}
};
上面這一版會在最後一個 case TLE,所以稍微來改進一下:
上一個實作有個很浪費時間的地方是在 merge 時,直接讓 ans = nums,還有讓 nums = ans,所以會不斷做整個 array copying,這邊只修改需要修改的地方,提升效率。
Copy class Solution {
public :
vector < int > sortArray ( vector < int > & nums) {
mergeSort (nums , 0 , nums . size () - 1 );
return nums;
}
private :
void mergeSort ( vector < int > & nums , int start , int end) {
if (start >= end)
return ;
int mid = start + (end - start) / 2 ;
mergeSort (nums , start , mid);
mergeSort (nums , mid + 1 , end);
merge (nums , start , mid , mid + 1 , end);
}
void merge ( vector < int > & nums , int l_start , int l_end , int r_start , int r_end) {
int l = l_start , r = r_start , cur = 0 ;
// Improved
vector <int> ans (l_end - l_start + 1 + r_end - r_start + 1 );
while (l <= l_end && r <= r_end) {
if ( nums [l] <= nums [r])
ans [cur ++ ] = nums [l ++ ];
else
ans [cur ++ ] = nums [r ++ ];
}
while (l <= l_end)
ans [cur ++ ] = nums [l ++ ];
while (r <= r_end)
ans [cur ++ ] = nums [r ++ ];
// Improved
for ( auto a : ans)
nums [l_start ++ ] = a;
}
};
效率提升到:
Runtime: 108 ms, faster than 16.72% of C++ online submissions for Sort an Array. Memory Usage: 40.3 MB, less than 5.55% of C++ online submissions for Sort an Array.
再加上一個判斷條件優化一下:
Copy class Solution {
public :
vector < int > sortArray ( vector < int > & nums) {
if ( nums . size () < 2 )
return nums;
mergeSort (nums , 0 , nums . size () - 1 );
return nums;
}
private :
void mergeSort ( vector < int > & nums , int start , int end) {
if (start >= end)
return ;
int mid = start + (end - start) / 2 ;
mergeSort (nums , start , mid);
mergeSort (nums , mid + 1 , end);
merge (nums , start , mid , mid + 1 , end);
}
void merge ( vector < int > & nums , int l_start , int l_end , int r_start , int r_end) {
int l = l_start , r = r_start , cur = 0 ;
vector <int> ans (l_end - l_start + 1 + r_end - r_start + 1 );
while (l <= l_end && r <= r_end) {
if ( nums [l] <= nums [r])
ans [cur ++ ] = nums [l ++ ];
else
ans [cur ++ ] = nums [r ++ ];
}
while (l <= l_end)
ans [cur ++ ] = nums [l ++ ];
while (r <= r_end)
ans [cur ++ ] = nums [r ++ ];
for ( auto a : ans)
nums [l_start ++ ] = a;
}
};
效率再度小小提升:
Runtime: 96 ms, faster than 19.47% of C++ online submissions for Sort an Array. Memory Usage: 40.4 MB, less than 5.55% of C++ online submissions for Sort an Array.
最後再把 code 寫得漂亮一點:
Copy class Solution {
public :
vector < int > sortArray ( vector < int > & nums) {
if ( nums . size () < 2 )
return nums;
mergeSort (nums , 0 , nums . size () - 1 );
return nums;
}
private :
void mergeSort ( vector < int > & nums , int start , int end) {
if (start >= end)
return ;
int mid = start + (end - start) / 2 ;
mergeSort (nums , start , mid);
mergeSort (nums , mid + 1 , end);
merge (nums , start , mid , mid + 1 , end);
}
void merge ( vector < int > & nums , int l_start , int l_end , int r_start , int r_end) {
int l = l_start , r = r_start , cur = 0 ;
vector <int> ans (l_end - l_start + 1 + r_end - r_start + 1 );
while (l <= l_end && r <= r_end) {
ans [cur ++ ] = nums [l] <= nums [r] ? nums [l ++ ] : nums [r ++ ];
}
while (l <= l_end)
ans [cur ++ ] = nums [l ++ ];
while (r <= r_end)
ans [cur ++ ] = nums [r ++ ];
for ( auto a : ans)
nums [l_start ++ ] = a;
}
};
Counting Sort
Counting sort 的概念滿直覺的,就是數每個數字出現幾次,然後再根據出現次數寫到答案中,因為 time complexity 是 O(N),所以很有效率。
Copy class Solution {
public :
vector < int > sortArray ( vector < int > & nums) {
if ( nums . size () < 2 )
return nums;
vector <int> table ( 50000 + 50000 + 1 );
for ( auto n : nums) table [n + 50000 ] ++ ;
int idx = 0 ;
for ( int i = 0 ; i < table . size (); i ++ ) {
if ( table [i] -- ) {
nums [idx ++ ] = i - 50000 ;
i -- ;
}
}
return nums;
}
};
執行起來的速度如下:
Runtime: 52 ms, faster than 97.46% of C++ online submissions for Sort an Array. Memory Usage: 16.5 MB, less than 22.22% of C++ online submissions for Sort an Array.