近期在閱讀一個開源的C++代碼。里面用到了大量的STL里面的東西。或許是自己一直用C而非常少用C++來實現算法的原因。STL里面大量的模板令人心煩。一直對STL的效率表示懷疑,但在網上搜到這樣一個帖子,說C的標准庫里面高速排序比STL的標准排序要慢!於是,便認真的看了下二者的源代碼,發現C++里面的std::sort綜合運用了部分高速排序和堆排序算法,而C標准庫里面用的是通用數據結構的高速排序,C標准庫里面的qsort之所以比std::sort慢。是由於C語言中為了適配全部的數據結構使用了空指針。以下以更為簡單的插入排序為例說明這個問題。
插入排序的算法實現代碼:
void insert_sort(int a[], int n) { int i, j; int t; for (i = 1; i < n; i++) { t = a[i]; j = i; while ((j > 0) && (a[j - 1] > t)) { a[j] = a[j - 1]; j--; } a[j] = t; } }
上述插入排序的實現僅僅能針對整數類型進行排序,假設數據類型是浮點型。則要自己又一次把代碼拷貝一份。而且更改函數名以及數據類型。
假設是雙精度的,又或者是對自己定義的結構體數組進行排序呢? 顯然,這不是一種非常好的解決方式。 而用空指針能夠解決問題。
通用數據類型的插入排序實現代碼:
void general_insert_sort(void* arr, int num_element, int element_bytes, int (*cmp_fun)(void* p1, void* p2)) { int i, j; int t[1024]; if (element_bytes > 4096){ return; } #define ELE(arr, i) (void*)(((unsigned)arr) + (i) * element_bytes) for (i = 1; i < num_element; i++) { memcpy(t, ELE(arr, i), element_bytes); j = i; while ((j > 0) && (cmp_fun(ELE(arr, j - 1), (void*)t))) { memcpy(ELE(arr, j), ELE(arr, j - 1), element_bytes); j--; } memcpy(ELE(arr, j), (void*)t, element_bytes); } }
上述通用插入排序的實現有一個限制。就是待排序數組里面每個元素的大小不能超過4k,當然對於簡單的系統提前定義好的數據類型,數組元素的大小最大為double,僅僅有8個字節,這是遠遠的足夠用的。假設你自己定義的結構體的大小太大,比如大於這里設置的4K,則沒有必要用此方法排序,由於此時數據移動會占用大部分時間,此時應該考慮用索引排序的方法。
上面的方法盡管攻克了隨意數據類型的問題,可是其效率並不怎么高。相對於上述第一段代碼而言,簡單的賦值語句必須得調用一個函數來拷貝數據。簡單的比較語句,則須要調用外部傳入一個函數指針得到比較結果。
這是效率低下的根本原因。
而C++模板參數的出現,僅僅須要寫一份代碼,編譯器依據你調用時候的數據類型自己主動生成新的代碼。其有用宏也能夠完畢通用的功能。這里給出C語言宏的代碼。C++模板的代碼也非常easy。
#define FIV_IMPLEMENT_INSETT_SORT(function_name, T, LT_CMP)\ void function_name(T* arr, int low, int high)\ {\ int i, j;\ T t;\ for (i = low + 1; i < high; i++) {\ t = arr[i];\ j = i;\ while ((j > low) && (LT_CMP(t, arr[j - 1]))) {\ arr[j] = arr[j - 1];\ j--;\ }\ arr[j] = t;\ }\ }
上面的宏定義能夠看做是一種模板定義,能夠用於隨意數據類型。
假設你要對整數進行排序。非常easy,用以下的兩個宏。一個宏定義比較運算。一個宏為函數定義:
#define CMP(a, b) ((a) < (b))
FIV_IMPLEMENT_INSETT_SORT(insert_sort_int, int, CMP)
這樣就有一個用於整數排序的函數insert_sort_int可用,假設是你自己定義的結構體類型,則相同僅僅須要寫這兩個宏就能夠了。
結尾:
用C++模板產生的代碼大小是不使用模板的非常多倍,而用C語言的空指針能夠支持隨意數據類型,代碼大小非常小,而用C語言的宏定義產生模板函數的代碼大小理論上和使用STL的大小是一樣的。
經過本人測試。隨便一個特定數據結構的高速排序遞歸實現,都比c++ stl里面的std::sort要快。