1. 程式人生 > >STL之劃分與排序演算法(Partions and Sorting)

STL之劃分與排序演算法(Partions and Sorting)

目錄

 

        STL之劃分與排序演算法(Partions and Sorting)

劃分演算法

一、is_partitoned

二、partition

三、partition_copy(beg, end, dest1, dest2, unaryPred)

四、partition_point(beg, end, unaryPred)

五、stable_partition(beg,end,unaryPred)

排序演算法

三、實現比較函式cmp

(1)基本資料型別陣列的排序

(2)結構體陣列的排序

(3)容器的排序



        STL之劃分與排序演算法(Partions and Sorting)

    對於序列中的元素進行排序,排序和劃分演算法提供了多種策略。

    每個排序和和劃分演算法都提供穩定和不穩定版本。穩定順豐保證保持相等元素的相對順序。由於穩定演算法會做更多工作,可能比不穩定版本慢得多並消耗跟多記憶體。

劃分演算法

    一個劃分演算法將輸入範圍中的元素劃分為兩組。第一組包含那些滿足給定謂詞的元素,第二組則包含不滿足謂詞的元素。例如,對於一個序列中的元素,我們可以根據元素是否是奇數或者單詞是否以大寫字母開頭來等劃分他們。這些演算法都要求雙向迭代器

謂詞 (Predicate) 要求描述可呼叫 (Callable) 物件返回可作為 bool 測試的值。

謂詞 (Predicate) 常用於接收輸入資料(單獨的物件/容器)和謂詞的演算法,然後在進一步行動時得到呼叫。 C++ 標準庫中的一些謂詞使用示例是:

  • std::all_of 、 std::any_of 、 std::none_of 接收元素範圍和謂詞為輸入。在每個單獨的輸入元素上呼叫謂詞,並且若謂詞分別對全部/任一/無元素返回 true 則返回 true 。

  • std::find_if

     接受元素序列和謂詞。返回序列中的首個謂詞對其返回的 true 的元素。

換言之,若演算法接收謂詞 (Predicate) pred 和迭代器 first ,則它應該能經由類似 if(pred(*first)) {...} 的構造,測試迭代器 first 所指向的型別。

函式物件 pred 不應當通過解引用的迭代器應用任何非 const 函式。此函式物件可以是指向函式的指標或擁有適合的函式呼叫運算子的型別的物件。

一、is_partitoned

The behavior of this function template is equivalent to:( 此函式模板的行為等效於:)

template <class InputIterator, class UnaryPredicate>

bool is_partitioned (InputIterator first, InputIterator last, UnaryPredicate pred)

{

while (first!=last && pred(*first)) {

++first;

}

while (first!=last) {

if (pred(*first)) return false;

++first;

}

return true;

}

返回值

若範圍 [first, last) 為空或以 p 劃分則為 true 。否則為 false 

二、partition

使用unaryPred劃分過的。返回滿足unaryPred的範圍的尾後迭代器。如果返回的迭代器不是end,則它指向的元素及其後的元素必須逗不滿足unaryPred

三、partition_copy(beg, end, dest1, dest2, unaryPred)

將滿足unaryPred的元素拷貝到dest1,並不滿足unaryPred的元素拷貝到dest2.返回一個迭代器pair,其first成員表示拷貝到dest1打元素的末尾,second表示拷貝到dest2的元素末尾。輸入序列與兩個目的序列都不能重疊。

四、partition_point(beg, end, unaryPred)

輸入序列必須是已經用unaryPred劃分過的。返回滿足unaryPred的範圍的尾後迭代器。如果返回的迭代器不是end,則它指向的元素及其後的元素必須都不滿足unaryPred

五、stable_partition(beg,end,unaryPred)

為穩定劃分演算法用法類似 

每個排序和和劃分演算法都提供穩定和不穩定版本。穩定順豐保證保持相等元素的相對順序。由於穩定演算法會做更多工作,可能比不穩定版本慢得多並消耗跟多記憶體。

排序演算法

    這些演算法要求隨機訪問迭代器。每個排序演算法都提供兩個過載的版本。一個版本用元素的<運算子來比較元素,另一個版本接受一個額外的引數來指定排序關係。partial_sort_copy返回一個指向目的位置的迭代器,其他排序演算法都返回void

 

    partial_sort和nth_element演算法都只進行部分排序工作,它們常用於不需要排序整個序列的場合。由於這些演算法工作量更少,它們通常比排序整個輸入序列的演算法更快。

 

    sort(beg,end)

    stabel_sort(beg,end)

    sort(beg,end,comp)

    stable_sort(beg,end,comp)

    排序整個範圍。

 

    is_sorted(beg,end)

    is_sorted(beg, end, comp)

    is_sorted_until(beg, end)

    is_sorted_until(beg, end, comp)

 

    is_sorted返回一個bool值,指出整個輸入序列是否有序。is_sorted_until在輸入序列中查詢最長初始有序子列,並返回序列的尾後迭代器。

    partial_sort(beg, mid, end)

    partial_sort(beg, mid, end, comp)

 

排序mid-beg個元素。即,如果mid-beg等於42,則此函式將值最下的42個元素有序放在序列前42個位置,當partial_sort完成後,從beg開始至mid之前的範圍中的元素就都已排好序了。已排序範圍中的元素範圍都不會比mid後的元素更大。未排       序    區域中的元素的順序是未指定的。

 

    partial_sort_copy(beg, end, destBeg, destEnd)

    partial_sort_copy(beg, end, destBeg, destEnd, comp)

 

排序輸入範圍中的元素,並將足夠多的已排序元素放到destBeg盒destEnd所指示的序列中。如果目的範圍的大小大於等於輸入範圍,則排序整個輸入序列並存入從destBeg開始的範圍。如果目的範圍的大小小於輸入範圍,則只拷貝輸入序列中與目的範圍一樣多的元素。

  

  演算法返回一個迭代器,指向目的範圍中已排序部分的尾後迭代器。如果目的序列的大小小於或等於輸入範圍,則返回destEnd。

    nth_element(beg, nth, end)

    nth_element(beg, nth, comp)

 

引數nth必須是一個迭代器指向輸入序列中的一個元素。執行nth_element後,此迭代器指向的元素恰好是整個序列排好後此位置上的值。序列中的元素會圍繞nth進行劃分:nth之前的元素都小於等於它,而之後的元素都大於等於它。

comp

二進位制函式,接受範圍中的兩個元素作為引數,並返回可轉換為的值bool返回的值表示作為第一個引數傳遞的元素是否被認為是在它定義的特定嚴格弱順序中的第二個引數之前

該函式不得修改其任何引數。

這可以是函式指標或函式物件。

 

三、實現比較函式cmp

 

// sort algorithm example#include <iostream> // std::cout

#include <algorithm> // std::sort

#include <vector> // std::vector

 

bool myfunction (int i,int j) { return (i<j); }

 

struct myclass {

bool operator() (int i,int j) { return (i<j);}

} myobject;

 

int main () {

int myints[] = {32,71,12,45,26,80,53,33};

std::vector<int> myvector (myints, myints+8); // 32 71 12 45 26 80 53 33

 

// using default comparison (operator <):

std::sort (myvector.begin(), myvector.begin()+4); //(12 32 45 71)26 80 53 33

 

// using function as comp

std::sort (myvector.begin()+4, myvector.end(), myfunction); // 12 32 45 71(26 33 53 80)

 

// using object as comp

std::sort (myvector.begin(), myvector.end(), myobject); //(12 26 32 33 45 53 71 80)

 

// print out content:

std::cout << "myvector contains:";

for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it)

std::cout << ' ' << *it;

std::cout << '\n';

 

return 0;

}

 

(1)基本資料型別陣列的排序

若比較函式不填,則預設按照從小到大的順序排序。下面是對int型陣列的排序:

 

#include<stdio.h>

#inclue <algorithm>

using namespace std;

 

int main(){

    int a[5]={3,1,4,2};

    sort(a,a+4);

    for(int i=0;i<4;i++){

        printf("%d ",a[i]);

    }

    return 0;

}

輸出結果:

1 2 3 4    

    如果想要從大到小來排序,則想要使用比較函式cmp來“告訴”sort何交換元素(讓元素的大小比較關係反過來)。還是上面的例子,這裡比較的元素是int型別,可以這樣寫:

 

#include <stdio.h>

#include <algrothm>

using namespace std;

bool cmp(int a,int b){

    return a>b;//可理解為當a>b時把a放在b前面

}

int  main(){

        int a[]={3,1,4,2};

        sort(a,a+4,cmp);

        for(int i=0;i<4;i++){

            printf("%d ",a[i]; //輸出4 3 2 1

    }

    return 0;

}

 

(2)結構體陣列的排序

現在定義瞭如下的結構體:

 

struct node{

    int x,y;

}ssd[10]

如果想將ssd陣列按照x從大到小排序(即進行一級排序),那麼可以這樣寫cmp函式:

 

bool cmp(node a,node b){

    return a.x>b.x;

}

示例如下:

#include<stdio.h>

#include <algorithm>

using namespace std;

struct node{

    int s,y;

}ssd[10];

bool cmp(node a,node b){

return a.x>b.x;//按x值從大到小對結構體陣列排序

}

int main(){

    ssd[0].x=2; //{2.2}

    ssd[0].y=2;

    ssd[1].x=1;//{1,3}

    ssd[1].y=3;

    ssd[2].x=3;//{3,1}

    ssd[2].y=1;

    sort(ssd,ssd+3,cmp); //排序

    for(int i=0;i<3;i++){

        printf("%d %d\n",ssd[i].x,ssd[i].y);

    }

    return 0;

}

輸出結果:

3 1

2 2

1 3

而如果想先按x從大到小排序,但當x相等的情況下,按照y的大小從小到大來排序(即進行二級排序),那麼cmp的寫法是:

 

bool cmp(node a, node b){

    if(a.x!=b.x);     //不相等時按x從大到小排序

    else return a.y<b.y;     //x相等時按y從小到大排序

}

(3)容器的排序

在STL標準容器中,只有vector、string。deque是可以使用sort的。這是因為像set、map這種容器是用紅黑樹實現的,元素本身有序,故不允許使用sort排序。

    下面以vector為例:

 

#include <stdio.h>

#include <vector>

#include <algorithm>

using namespace std;

bool cmp(int a,int b){ //因為vector中的元素為int 型,因此任然是int的比較

    retrun a>b;

}

int main(){

    vector<int> vi;

    vi.push_back(3);

    vi.push_back(1);

    vi.push_back(2);

    sort(vi.begin(),vi.end(),cmp);  //對整個vector排序

    for(int i=0;i<3;i++){

    printf("%d",vi[i]);

    }

    retrun 0;

}

輸出結果:

3 2 1

 

stringd中的排序:

 

#include <iostream>

#include <string>

#include <algorithm>

using namespace std;

int main(){

    string str[3]={"bbbb","cc","aaa"};

    sort(str,str+3);    //將string型陣列按字典序從小到大輸出

    for(int i=0;i<3;i++){

        cout<<str[i]<<endl;

    }

    return 0;

}

上面的程式碼輸出如下:

aaa

bbbb

cc

如果上面這個例子中,需要按字串長度從小到大排序,那麼可以這樣寫:

 

#include <iostream>

#include <string>

#include <algorithm>

using namespace std;

bool cmp(string str1,string str2){

    return str1.length()<str2.length();  //按string的長度從小到大排序

}

int main(){

    string str[3]={"bbbb","cc","aaa"};

        sort(str,str+3,cmp);

        for(int i=0;i<3;i++){

            cout<<str[i]<<endl;

        }

        return 0;

}

輸出結果:

cc 

aaa

bbbb

(如果相等保持原序列,繼續往後排序,其實就是comp函式的定義)