一般來說,我們對於c++和python的印象是,
c++的程式執行速度較快,python的程式執行速度較慢,
我在leetcode上刷題百題以上,
也幾乎都是這樣的結論
但有一天,我在leetcode上刷到一題跟「排序」相關的問題
(973. K Closest Points to Origin)
同樣使用內建的排序函數,
做完之後卻發現c++比python還慢了2倍以上
補充: 附上我在leetcode上的解法
class Solution {
public:
vector<vector<int>> kClosest(vector<vector<int>>& points, int K) {
sort(points.begin(), points.end(), [](auto p1, auto p2){
return (p1[0]*p1[0]+p1[1]*p1[1])< (p2[0]*p2[0]+p2[1]*p2[1]);});
return {points.begin(), points.begin()+K};
}
};
class Solution:
def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]:
points.sort(key=lambda p: p[0]*p[0]+p[1]*p[1])
return points[:K]
這個結果十分新奇,難道c++的排序函數比python慢嗎?
於是我自己寫了程式來重現這個效果,
測試的平台都是用repl.it
c++排序程式:
#include <iostream>
#include <vector>
#include <algorithm> // sort()函數
#include <cstdlib> // 亂數相關函數
#include <ctime> // 時間相關函數
using namespace std;
int main()
{
srand( time(NULL) ); /* 設定亂數種子 */
vector<vector<int>> arr(100000, vector<int>(2));
for(int i=0; i<arr.size(); i++)
{
arr[i][0] = rand();
arr[i][1] = rand();
}
clock_t start, end; // 儲存時間用的變數
start = clock(); // 計算開始時間
sort(arr.begin(), arr.end(), [](auto p1, auto p2)
{
return (p1[0]*p1[0]+p1[1]*p1[1])< (p2[0]*p2[0]+p2[1]*p2[1]);
});
end = clock(); // 計算結束時間
double cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; // 計算實際花費時間
cout << "程式執行時間:" << cpu_time_used <<endl;
return 0;
}
python的排序程式:
import time
import random
L = [[random.randint(0, 1<<31-1), random.randint(0, 1<<31-1)] for i in range(100000)]
tStart = time.time() #計時開始
L.sort(key=lambda p: p[0]*p[0]+p[1]*p[1])
tEnd = time.time() #計時結束
print(f"程式執行時間= {tEnd - tStart:.4f}秒") #四捨五入到小數點後四位
一測試之後非常驚人,
同樣在陣列裡面放十萬個小陣列,
使用自定義排序的方式,
陣列p[0]*p[0]+p[1]*p[1]
的值愈小,排序上愈前面,
c++的排序速度比python慢了數倍以上,
為什麼c++在各方面似乎都比python快,
在自定義的排序上感覺慢這麼多呢?
看了一級屠豬士的 Timsort
和海綿寶寶的 Introsort
我去 Google 了時間複雜度
兩者最壞都是 O(n log n)
感覺起來應該是差不多的速度
我把 lambda 改成一般的函數
時間就和 python 差不多
可能 C++ 對 lambda 的優化沒有很好
#include <iostream>
#include <vector>
#include <algorithm> // sort()函數
#include <cstdlib> // 亂數相關函數
#include <ctime> // 時間相關函數
using namespace std;
bool compare(vector<int> &p1, vector<int> &p2)
{
return (p1[0]*p1[0]+p1[1]*p1[1]) < (p2[0]*p2[0]+p2[1]*p2[1]);
}
int main()
{
srand( time(NULL) ); /* 設定亂數種子 */
vector<vector<int>> arr(100000, vector<int>(2));
for(int i=0; i<arr.size(); i++)
{
arr[i][0] = rand();
arr[i][1] = rand();
}
clock_t start, end; // 儲存時間用的變數
start = clock(); // 計算開始時間
sort(arr.begin(), arr.end(), compare);
end = clock(); // 計算結束時間
double cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; // 計算實際花費時間
cout << "程式執行時間:" << cpu_time_used <<endl;
return 0;
}
謝謝解答,很實用~
我將leetcode上的解改為一般的函數,
而不直接用lambda,
速度就比python還快了,
修改後的解:
class Solution {
static bool compare(vector<int> &p1, vector<int> &p2)
{
return (p1[0]*p1[0]+p1[1]*p1[1]) < (p2[0]*p2[0]+p2[1]*p2[1]);
}
public:
vector<vector<int>> kClosest(vector<vector<int>>& points, int K) {
sort(points.begin(), points.end(), compare);
return {points.begin(), points.begin()+K};
}
};
我又測了一下
發現問題好像不是出在 lambda 身上
應該是 參數複製 的問題
我把 p1、p2 都改成傳址
速度就變快了
sort(arr.begin(), arr.end(), [](auto &p1, auto &p2)
{
return (p1[0]*p1[0]+p1[1]*p1[1])< (p2[0]*p2[0]+p2[1]*p2[1]);
});
後來想想 Python 也是用 lambda
怎麼會沒有效能損耗
不太可能 Python 的優化和 C++ 差這麼多
如果真的是這樣 C++ 就要好好檢討了
對耶~ 你說的非常好,
我忽略這個基礎的點了,
是call by reference(傳址)的問題,
跟演算法本身與lambda無關,
太感謝您了~
我把 lambda 改成一般的函數
時間就和 python 差不多
可能 C++ 對 lambda 的優化沒有很好
#include <iostream>
#include <vector>
#include <algorithm> // sort()函數
#include <cstdlib> // 亂數相關函數
#include <ctime> // 時間相關函數
using namespace std;
bool compare(vector<int> &p1, vector<int> &p2)
{
return (p1[0]*p1[0]+p1[1]*p1[1]) < (p2[0]*p2[0]+p2[1]*p2[1]);
}
int main()
{
srand( time(NULL) ); /* 設定亂數種子 */
vector<vector<int>> arr(100000, vector<int>(2));
for(int i=0; i<arr.size(); i++)
{
arr[i][0] = rand();
arr[i][1] = rand();
}
clock_t start, end; // 儲存時間用的變數
start = clock(); // 計算開始時間
sort(arr.begin(), arr.end(), compare);
end = clock(); // 計算結束時間
double cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; // 計算實際花費時間
cout << "程式執行時間:" << cpu_time_used <<endl;
return 0;
}
我猜也是 lambda 的原因 .....
嗨~ fysh711426 邦友您好,感謝你的分享討論,我覺得你的意見蠻好的,歡迎可直接回答
這句話是錯的
C++的程式執行速度較快
正確的說法應該是
會寫C++的人, C++的程式執行速度較快
可惜的是99%寫C++的人都是不會寫C++的人,
包括我.
而且你用的函式是C++ 11的函式,
那已經是比較後期,
改得比較高階的C++了,
高階語言的特性就是 上手的容易度 > 程式的效率,
當然魚跟熊掌兩個都能兼得是最好,
但是常常是不能兼得的.