首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

善用標準庫,避免重複造輪子:C++ 排序實踐與跨語言對比

     編輯:關於C#

之前寫過一篇關於「避免重複代碼——知曉你的庫」的文章。今天心血來潮,趁著窗外雨聲淅瀝,繼續來聊聊這個話題。

面試題引發的思考

上週某公司來校招聘,C++ 筆試題中有一道要求對包含自定義結構體的 vector 進行排序。結構體包含兩個欄位:int num 和 string name;排序規則為先按 num 升序,若相同則按 name 升序。原題結構體並未重載 < 或 == 運算符,且 vector 存放的是實例而非指標。

聽說考完試的同學們在機房討論該如何手寫排序演算法。但這是 C++ 呀,標準庫 std::sort 早已解決此類問題,何必重複造輪子?

C++98 風格:特化 std::less

最直接的做法是為 Person 特化 std::less,作為比較函子傳給 std::sort:

#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

struct Person {
    int num;
    string name;
    Person(int num, string name) : num(num), name(name) {}
};

namespace std {
    template<>
    struct less<Person> {
        bool operator()(const Person& p1, const Person& p2) {
            if (p1.num < p2.num) return true;
            if (p1.num == p2.num && p1.name < p2.name) return true;
            return false;
        }
    };
}

struct printElement {
    void operator()(const Person& p) {
        cout << "Person: " << p.num << ", " << p.name << endl;
    }
};

int main() {
    vector<Person> v;
    v.push_back(Person(2, "smith"));
    v.push_back(Person(1, "john"));
    v.push_back(Person(2, "micheal"));
    v.push_back(Person(1, "micheal"));
    v.push_back(Person(3, "albert"));
    sort(v.begin(), v.end(), less<Person>());
    for_each(v.begin(), v.end(), printElement());
    return 0;
}

輸出結果:

Person: 1, john
Person: 1, micheal
Person: 2, micheal
Person: 2, smith
Person: 3, albert

這樣就能利用 STL 高效、穩定的排序實現,避免手寫演算法帶來的 Bug 風險與維護成本。當然,程序員仍需掌握排序原理,但在生產環境中,優先使用成熟庫才是明智之舉。

C++11/14 風格:Lambda 與範圍 for

隨著 C++11 標準發布,語法更加簡潔。使用 Lambda 表達式內聯比較邏輯,搭配範圍基礎的 for 迴圈遍歷:

#include <algorithm>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

struct Person {
    int num;
    string name;
    Person(int num, string name) : num(num), name(name) {}
};

int main() {
    vector<Person> v;
    v.push_back(Person(2, "smith"));
    v.push_back(Person(1, "john"));
    v.push_back(Person(2, "micheal"));
    v.push_back(Person(1, "micheal"));
    v.push_back(Person(3, "albert"));

    sort(v.begin(), v.end(), [](const Person& p1, const Person& p2) {
        if (p1.num < p2.num) return true;
        if (p1.num == p2.num && p1.name < p2.name) return true;
        return false;
    });

    for (const Person& p : v) {
        cout << "Person: " << p.num << ", " << p.name << endl;
    }
    return 0;
}

註:VS2010 CTP 已支援部分 C++11 特性(如 Lambda),但範圍 for 因依賴 Concepts 機制(當時未定案)而暫不支援。

跨語言對比:F# 與 Ruby 的簡潔性

若結構體有公認的自然順序,直接重載 operator< 即可使用兩參數版 sort()。但題目限制不得修改結構體,故採用上述方式。

順便對比一下函數式語言與腳本語言的表達力:

F# (Tuple + List.sort)

let l = [(2, "smith"); (1, "john"); (2, "micheal"); (1, "micheal"); (3, "albert")]
List.sort compare l
// val it : (int * string) list = [(1, "john"); (1, "micheal"); (2, "micheal"); (2, "smith"); (3, "albert")]

Ruby (Array + sort)

l = [[2, "smith"], [1, "john"], [2, "micheal"], [1, "micheal"], [3, "albert"]]
l.sort
#=> [[1, "john"], [1, "micheal"], [2, "micheal"], [2, "smith"], [3, "albert"]]

腳本語言若連這點便利性都沒有,存在的意義何在?

牢騷到此結束,核心觀點不變:知曉你的庫,避免重複造輪子。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved