排序函數:
函數名 | 功能描述 |
sort | 對給定區間所有元素進行排序 |
stable_sort | 對給定區間所有元素進行穩定排序 |
partial_sort | 對給定區間所有元素部分排 |
partial_sort_copy | 對給定區間複製並排序 |
nth_element | 找出給定區間的某個位置對應的元素 |
is_sorted | 判斷一個區間是否已經排好序 |
partition | 使得符合某個條件的元素放在前面 |
stable_partition | 相對穩定的使得符合某個條件的元素放在前面 |
sort:
要使用此函數只需用#include <algorithm> sort即可使用,語法描述爲:
int main()
{
int a[]={2,4,1,23,5,76,0,43,24,65};
int i;
for(i=0;i<10;i++)
cout<<a[i]<<" ";
cout<<endl;
sort(a,a+10);
for(i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
輸出結果:2 4 1 23 5 76 0 43 24 65
0 1 2 4 5 23 24 43 65 76
---------------------------------
對於list容器,這個方法也適用,把compare作爲sort的參數就可以了,即:sort(compare).
1)自己編寫compare函數:
bool compare(int a,int b)
{
return a>b; //降序排列,如果改爲return a<b,則爲升序
}
輸出結果2 4 1 23 5 76 0 43 24 65
76 65 43 24 23 5 4 2 1 0
---------------------------------
class compare
{
private:
Enumcomp comp;
public:
compare(Enumcomp c):comp(c) {};
bool operator () (int num1,int num2)
{
switch(comp)
{
case ASC:
return num1<num2;
case DESC:
return num1>num2;
}
}
};
接下來使用 sort(begin,end,compare(ASC)實現升序,sort(begin,end,compare(DESC)實現降序標準庫裏已經有現成的了,就在functional裏,include進來就行了。functional提供了一堆基於模板的比較函數對象。
它們是(看名字就知道意思了):equal_to<Type>、not_equal_to<Type>、greater<Type>、greater_equal<Type>、less<Type>、less_equal<Type>。
對於這個問題來說,greater和less就足夠了,直接拿過來用:
降序:sort(begin,end,greater<data-type>()).
int main()
{
int a[]={2,4,1,23,5,76,0,43,24,65};
int i;
for(i=0;i<10;i++)
cout<<a[i]<<" ";
cout<<endl;
sort(a,a+10,greater<int>()); //升序爲less<int>()
for(i=0;i<10;i++)
cout<<a[i]<<" ";
return 0;
}
4)既然有迭代器,如果是string 就可以使用反向迭代器來完成逆序排列,程序如下:
int main()
{
string str("cvicses");
string s(str.rbegin(),str.rend());
cout << s <<endl;
return 0;
}
stable_sort:
stable_sort 函數與sort函數用法相同。這兩個函數的原理都是快速排序,時間複雜度在所有排序中最低,爲O(nlog2n) ;
區別是stable_sort 是穩定排序,也就是stable_sort函數遇到兩個數相等時,不對其交換順序;
這個應用在數組裏面不受影響,當函數參數傳入的是結構體時,會發現兩者之間的明顯區別;
partial_sort:
有一個賽跑成績的集合,我們想知道前三名的成績但並不關心其他名次的次序,可以這樣對這個序列進行排序。
partial_sort(scores.begin(),scores.begin()+3,scores.end());
#include <vector>
#include <iterator>
#include <iostream>
#include <algorithm>
#include <functional>
#include <cstdlib>
#include <time.h>
using namespace std;
int rand_int()
{
return rand()%100;
}
void print(vector<int> &v,const char* s)
{
cout<<s<<endl;
copy(v.begin(),v.end(),ostream_iterator<int>(cout," "));
cout<<endl;
}
bool cmp(int &a, int &b)
{
if(a>b)
return true;
return false;
}
class compare{
public:
bool operator()(const int &a,const int &b)
{
if(a<b)
return true;
return false;
}
};
int main()
{
srand(time(NULL));
vector<int> v;
generate_n(back_inserter(v),10,rand_int);
print(v,"產生10個隨機數");
partial_sort(v.begin(),v.begin()+4,v.end());
print(v,"局部遞增排序");
partial_sort(v.begin(),v.begin()+4,v.end(),cmp);
print(v,"局部遞減排序");
partial_sort(v.begin(),v.begin()+4,v.end(),compare());
print(v,"局部遞增排序");
return 0;
}
測試結果:
產生10個隨機數
69 54 33 50 13 52 54 61 29 5
局部遞增排序
5 13 29 33 69 54 54 61 52 50
局部遞減排序
69 61 54 54 5 13 29 33 52 50
局部遞增排序
5 13 29 33 69 61 54 54 52 50
----------------------------------------
通過程序可以看到兩次局部遞增排序並不相同,因爲partial_port不是穩定排序算法。在只需要最大或最小的幾個值時,partial_port比其他排序算法快。
partial_sort_copy:
原型:
template<class InputIterator, RandomAccessIterator> inline
RandomAccessIterator partial_sort(InputIterator first1,
InputIterator last1,
RandomAccessIterator first2,
RandomAccessIterator last2)
說明:
partial_sort_copy其實是copy和partial_sort的組合。被排序(被複制)的數量是[first, last)和[result_first, result_last)中區間較小的那個。如果[result_first, result_last)區間大於[first, last)區間,那麼partial_sort相當於copy和sort的組合。
示例代碼:
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
void main()
{
const int VECTOR_SIZE = 8 ;
// Define a template class vector of int
typedef vector<int, allocator<int> > IntVector ;
//Define an iterator for template class vector of strings
typedef IntVector::iterator IntVectorIt ;
IntVector Numbers(VECTOR_SIZE) ;
IntVector Result(4) ;
IntVectorIt start, end, it ;
// Initialize vector Numbers
Numbers[0] = 4 ;
Numbers[1] = 10;
Numbers[2] = 70 ;
Numbers[3] = 30 ;
Numbers[4] = 10;
Numbers[5] = 69 ;
Numbers[6] = 96 ;
Numbers[7] = 7;
start = Numbers.begin() ; // location of first
// element of Numbers
end = Numbers.end() ; // one past the location
// last element of Numbers
cout << "Before calling partial_sort_copy\n" << endl ;
// print content of Numbers
cout << "Numbers { " ;
for(it = start; it != end; it++)
cout << *it << " " ;
cout << " }\n" << endl ;
// sort the smallest 4 elements in the Numbers
// and copy the results in Result
partial_sort_copy(start, end, Result.begin(), Result.end()) ;
cout << "After calling partial_sort_copy\n" << endl ;
cout << "Numbers { " ;
for(it = start; it != end; it++)
cout << *it << " " ;
cout << " }\n" << endl ;
cout << "Result { " ;
for(it = Result.begin(); it != Result.end(); it++)
cout << *it << " " ;
cout << " }\n" << endl ;
}
測試結果:
Before calling partial_sort_copy
Numbers { 4 10 70 30 10 69 96 7 }
After calling partial_sort_copy
Numbers { 4 10 70 30 10 69 96 7 }
Result { 4 7 10 10 }
-------------------------------------------------
nth_element:
簡單的說nth_element算法僅排序第nth個元素(從0開始的索引)
如iarray [first,last) 元素區間
排序後 iarray[nth] 就是第nth大的元素(從0開始)
要注意的是[first,nth) [nth,last)內 的大小循序還不一定
只能確定iarray[nth]是第nth大的元素。
當然 [first,nth) 肯定是不大於 [nth,last)的。
簡單測試代碼如下
要注意的是,此函數只是將第nth大的元素排好了位置,但並沒有返回值
所以要知道第nth大的元素 還得進行一步,cout<<iarray[nth]<<endl; nth既那個位子
<pre name="code" class="cpp">#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int iarray[]={5,6,15,89,7,2,1,3,52,63,12,64,47};
int len=sizeof(iarray)/sizeof(int);
int i;
for(i=0;i<len;i++)
cout<<iarray[i]<<" ";
nth_element(iarray,iarray+6,iarray+len); //排序第6個元素
cout<<endl;
for(i=0;i<len;i++)
cout<<iarray[i]<<" ";
cout<<endl;
cout<<"第6-th個元素: "<<iarray[6]<<endl;
}
測試結果:
5 6 15 89 7 2 1 3 52 63 12 64 47
5 3 1 2 6 7 12 15 47 63 52 64 89
第6-th個元素: 12
---------------------------------------------
is_sorted:
is_sorted用於判斷一個區間是否已經有序,和排序一樣,可以自己定義比較函數。
但是,正如文章題目所說的一樣,is_sorted是SGI STL的擴展,在現在的GCC下並沒有(VS下也沒有),所以,爲了保證代碼的可移植性,最好不要使用這個函數。
Partition:
作用:Partition 函數用於返回一個 Variant (String),指定一個範圍,在一系列計算的範圍中指定的數字出現在這個範圍內。
函數的語法格式:
Partition(number, start, stop, interval)
Partition 函數的語法含有下面這些命名參數:部分描述
number必要參數。整數,在所有範圍中判斷這個整數是否出現。
start必要參數。整數,數值範圍的開始值,這個數值不能小於 0。
stop必要參數。整數,數值範圍的結束值,這個數值不能等於或小於 start。
說明:
Partition 函數會標識 number 值出現的特定範圍,並返回一個 Variant (String) 來描述這個範圍。
Partition 函數在查詢中是最有用的。可以創建一個選擇查詢顯示有多少定單落在幾個變化的範圍內,例如,定單數從 1 到 1000、1001 到 2000,以此類推。
解決問題:
快速排序算法裏的partition函數用來解決這樣一個問題:給定一個數組arr[]和數組中任意一個元素a,重排數組使得a左邊都小於它,右邊都不小於它。
// arr[]爲數組,start、end分別爲數組第一個元素和最後一個元素的索引
// povitIndex爲數組中任意選中的數的索引
int partition(int arr[], int start, int end, int pivotIndex)
{
int pivot = arr[pivotIndex];
swap(arr[pivotIndex], arr[end]);
int storeIndex = start;
//這個循環比一般的寫法簡潔高效,呵呵維基百科上看到的
for(int i = start; i < end; ++i) {
if(arr[i] < pivot) {
swap(arr[i], arr[storeIndex]);
++storeIndex;
}
}
swap(arr[storeIndex], arr[end]);
return storeIndex;
}
stable_partition:
stable_partition 就是partition排序算法的穩定算法,區別於 sort和stable_sort的區別是一樣
選擇合適的排序函數
爲什麼要選擇合適的排序函數?可能你並不關心效率(這裏的效率指的是程序運行時間), 或者說你的數據量很小, 因此你覺得隨便用哪個函數都無關緊要。
其實不然,即使你不關心效率,如果你選擇合適的排序函數,你會讓你的代碼更容易讓人明白,你會讓你的代碼更有擴充性,逐漸養成一個良好的習慣,很重要吧 。
如果你以前有用過C語言中的qsort, 想知道qsort和他們的比較,那我告訴你,qsort和sort是一樣的,因爲他們採用的都是快速排序。從效率上看,以下幾種sort算法的是一個排序,效率由高到低(耗時由小變大):
- partion
- stable_partition
- nth_element
- partial_sort
- sort
- stable_sort
- 若需對vector, string, deque, 或 array容器進行全排序,你可選擇sort或stable_sort;
- 若只需對vector, string, deque, 或 array容器中取得top n的元素,部分排序partial_sort是首選.
- 若對於vector, string, deque, 或array容器,你需要找到第n個位置的元素或者你需要得到top n且不關係top n中的內部順序,nth_element是最理想的;
- 若你需要從標準序列容器或者array中把滿足某個條件或者不滿足某個條件的元素分開,你最好使用partition或stable_partition;
- 若使用的list容器,你可以直接使用partition和stable_partition算法,你可以使用list::sort代替sort和stable_sort排序。若你需要得到partial_sort或nth_element的排序效果,你必須間接使用。正如上面介紹的有幾種方式可以選擇。