所以我詳細的問題是,我怎麼能儘快找到合適的案例?
你已經很少「如果不是...別的小」規則,所以性能是不是一個問題,沒有辦法,也沒有任何需要增加速度。一系列if
可以很好地完成這項工作。除非你實際測量了速度並發現了瓶頸。然而,從計算機科學的角度來看,有可能提出一種解決方案,它可以提供更好的計算複雜度,使得必要的比較操作的數量將按比例減少,從而得到更大的n,即你有更多的規則。
讓我們來看看。您的「如果小於... else」規則構成了某些範圍,並且您的if
的主體都使用不同的參數執行相同的操作。
這種情況可以被描繪成一個映射,其中每個範圍的末尾映射到一個參數集。在C++:
struct ColorArguments { int a; int b; int c; int d; };
std::map<int, ColorArguments> ranges;
地圖將被如下填寫:
ranges[100] = { 255, 0 , 0 , 255 };
ranges[1000] = { 0, 255 , 0 , 255 };
ranges[std::numeric_limits<int>::max()] = { 0, 0, 0, 255 };
事實上,而不是加油吧,你倒是應該初始化它,讓它const
:
std::map<int, ColorArguments> const ranges = {
{ 100, { 255, 0 , 0, 255 } },
{ 1000, { 0, 255 , 0, 255 } },
{ std::numeric_limits<int>::max(), { 0, 0, 0, 255 } }
};
最後,upper_bound
成員函數可以用來給你適當的ColorArguments
對象。該函數返回一個迭代器到第一個元素,其鍵大於指定值。
例如,在此映射中,搜索500會給你一個指向帶有鍵1000的元素的指針,因爲1000是第一個大於500的鍵。
upper_bound
有對數的複雜性,這是相當不錯的,比你原來的if-else
鏈的線性複雜度更好,儘管潛在的編譯器優化技術可以把這一線性代碼轉換成更復雜的東西。
auto const iter = ranges.upper_bound(m_errorNumber);
auto const& colors = iter->second;
說明了如何使用std::numeric_limits<int>::max()
(你的機器上的最大可能int
)作爲地圖的關鍵避免了特殊處理upper_bound
返回ranges.end()
(工作除非輸入本身可能是std::numeric_limits<int>::max()
,在這種情況下,你確實需要一些特殊的處理)。
下面是一個完整的例子:
#include <map>
#include <limits>
#include <iostream>
struct ColorArguments { int a; int b; int c; int d; };
void setColor(int a, int b, int c, int d)
{
std::cout << a << ", " << b << ", " << c << ", " << d << "\n";
}
int main()
{
std::map<int, ColorArguments> const ranges = {
{ 100, { 255, 0 , 0, 1 } },
{ 1000, { 0, 255 , 0, 2 } },
{ std::numeric_limits<int>::max(), { 0, 0, 0, 3 } }
};
int const errorNumber = 500;
auto const iter = ranges.upper_bound(errorNumber);
setColor(
iter->second.a,
iter->second.b,
iter->second.c,
iter->second.d
);
}
算法的複雜性之外,該解決方案也變爲靜態的,硬編碼if-else
邏輯進入數據,其可以被修改或在運行時動態地讀取。即使你不用它來解決你的具體問題,這也是一個需要記住的技巧。
沒有,真的沒有,但也許有一個更好的方法,我怎麼能做到這一點 – Gykonik
如果是有區別的,它很可能小到不值得努力。你有沒有分析你的程序,看看實際的瓶頸在哪裏? –
你真的低估了計算機能做這種微不足道的操作的速度。我想象一個'int'比較會轉化爲1或2個ASM指令。 –