![](/img/trans.png)
[英]Given a std::set::iterator, get an iterator pointing to the next element
[英]Get the closest element to a given element in an std::set
我有一組(排序的) unsigned int
。 我需要找到最接近給定數字的元素。
我正在尋找使用標准庫的解決方案,我的第一個解決方案是使用二進制搜索,但 STL 的實現僅在元素存在時才返回。 這篇文章Find Closest Element in a Set很有幫助,我實現了一個基於std::lower_bound
方法的解決方案,
(*假設集合有超過 2 個元素,則不進行空/邊界檢查):
#include <iostream>
#include<set>
#include<algorithm>
#include<cmath>
int main()
{
std::set<unsigned int> mySet = {34, 256, 268, 500, 502, 444};
unsigned int searchedElement = 260;
unsigned int closestElement;
auto lower_bound = mySet.lower_bound(searchedElement);
if (lower_bound == mySet.end()){
closestElement = *(--lower_bound);
}
std::set<unsigned int>::iterator prevElement = --lower_bound;
bool isPrevClosest = std::abs(*prevElement - searchedElement) > std::abs(*lower_bound - searchedElement);
closestElement = isPrevClosest ? *prevElement : *lower_bound;
std::cout << closestElement << std::endl;
return 0;
}
有沒有更簡單更標准的解決方案?
我認為沒有比使用.lower_bound
更好的解決方案了。 您可以將算法包裝到 function 模板中:
template<typename Set>
auto closest_element(Set& set, const typename Set::value_type& value)
-> decltype(set.begin())
{
const auto it = set.lower_bound(value);
if (it == set.begin())
return it;
const auto prev_it = std::prev(it);
return (it == set.end() || value - *prev_it <= *it - value) ? prev_it : it;
}
此 function 正確處理所有極端情況(空集、一個元素、第一個元素、最后一個元素)。
例子:
std::set<unsigned int> my_set{34, 256, 268, 500, 502, 444};
std::cout << *closest_element(my_set, 26); // Output: 34
std::cout << *closest_element(my_set, 260); // Output: 256
std::cout << *closest_element(my_set, 620); // Output: 502
請注意,您的代碼中的std::abs
(幾乎)什么都不做:它的參數具有無符號類型並且始終為非負數。 但是我們知道std::set
元素是有序的,因此我們知道*prev_it <= value <= *it
,並且不需要std::abs()
。
您可以使用 std::min_element(): 作為比較器,給它一個 lambda 返回絕對差異,例如
std::min_element(mySet.begin(), mySet.end(), [searchedElement](const unsigned int a, const unsigned int b) {
return std::abs(searchedElement - a) < std::abs(searchedElement - b);
});
但是,我確實認為這將不再適用二進制搜索......
編輯:此外,如下面的評論中所述,當x < y
時,無符號整數值的std::abs(x - y)
可能會返回意外大的 integer 。
std::set
容器適用於查找相鄰元素,即查找在給定元素之后或之前的元素。 考慮到您面臨的問題:
我正在尋找使用標准庫的解決方案,我的第一個解決方案是使用二進制搜索,但 STL 的實現僅在元素存在時才返回。
仍然有一種方法可以在不改變邏輯的情況下遵循:如果集合中不存在您想要找到的最接近的元素,那么您只需將其插入集合中(它需要對數時間的大小放)。 接下來,您將找到與剛剛添加的元素最近的元素。 最后,完成后將其從集合中移除,以使集合保持與之前相同。
當然,如果元素已經在集合中,則無需向集合中插入或移除任何內容。 因此,您需要跟蹤是否添加了該元素。
下面的 function 是上面闡述的思想的一個例子:
#include <set>
unsigned int find_closest_element(std::set<unsigned int> s, unsigned int val) {
bool remove_elem = false;
auto it = s.find(val);
// does val exist in the set?
if (s.end() == it) {
// element does not exist in the set, insert it
s.insert(val);
it = s.find(val);
remove_elem = true;
}
// find previous and next element
auto prev_it = (it == s.begin()? s.end(): std::prev(it));
auto next_it = std::next(it);
// remove inserted element if applicable
if (remove_elem)
s.erase(it);
unsigned int d1, d2;
d1 = d2 = std::numeric_limits<unsigned int>::max();
if (prev_it != s.end())
d1 = val - *prev_it;
if (next_it != s.end())
d2 = *next_it - val;
return d1 <= d2? *prev_it: *next_it;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.