如何在不刪除最大元素並再次搜索的情況下找到上述內容?有沒有更有效的方法來做到這一點?這些元素是否重複並不重要。查找範圍內的最大和第二大元素
回答
for (e: all elements) {
if (e > largest) {
second = largest;
largest = e;
} else if (e > second) {
second = e;
}
}
你既可以初始化largest
和second
到合適的下界,或在列表中的前兩個項目(檢查哪一個更大,並且不要忘記檢查,如果列表中有至少兩個項目)
從n..m創建一個子列表,排序,上去下來。然後抓住前兩個元素。從原始列表中刪除這些元素。
使用partial_sort?
std::partial_sort(aTest.begin(), aTest.begin() + 2, aTest.end(), Functor);
一個例子:
std::vector<int> aTest;
aTest.push_back(3);
aTest.push_back(2);
aTest.push_back(4);
aTest.push_back(1);
std::partial_sort(aTest.begin(), aTest.begin()+2,aTest.end(), std::greater<int>());
int Max = aTest[0];
int SecMax = aTest[1];
+1我不知道有關partial_Sort。但如果他想保留原始列表的順序,則不起作用。 – 2009-09-11 19:13:10
你可以使用partial_sort_copy作爲 – 2009-09-11 19:16:26
這不會讓你獲得最小的元素嗎?使用不同的比較運算符很容易修復。 +1 – rmeador 2009-09-11 19:22:43
讓我們假設你的意思是在列表中找到最大的兩個獨特的價值觀。
如果列表已經排序,那麼就看看倒數第二個元素(或者說,從最終尋找的倒數第二個值重複)。
如果列表未排序,那就不必對它進行排序。排序最好是O(n lg n)。簡單的線性迭代是O(n),所以剛過跟蹤元素循環:
v::value_type second_best = 0, best = 0;
for(v::const_iterator i=v.begin(); i!=v.end(); ++i)
if(*i > best) {
second_best = best;
best = *i;
} else if(*i > second_best) {
second_best = *i;
}
當然還有其他的標準,而這些可以全部投入到循環內的測試。但是,如果您的意思是應該找到兩個都具有相同最大值的元素,則必須考慮如果三個或更多元素都具有最大值,或者如果兩個或更多個元素具有第二大值,會發生什麼情況。
您可以掃描一遍列表,並保存第一和第二值,具有O(n)的效率,同時排序是O(n log n)的。
編輯:
我認爲這部分的排序是O(n日誌k)的
答案取決於如果你只想值,或也可以在值指向迭代器。
@ will回答的小修改。
v::value_type second_best = 0, best = 0;
for(v::const_iterator i=v.begin(); i!=v.end(); ++i)
{
if(*i > best)
{
second_best = best;
best = *i;
}
else if (*i > second_best)
{
second_best = *i;
}
}
nth_element(開始,開始+ N,端,比較)放置,這將是第n個元素(其中,「第一」是「第0」)如果[範圍開始,結束)的位置進行分選開始+並確保[begin,begin + n)中的所有內容都出現在排序列表中的第n個元素之前。所以,你想要的代碼是:
nth_element(container.begin(),
container.begin()+1,
container.end(),
appropriateCompare);
這會在你的情況下工作得很好,因爲你只想找兩個最大。假設你appropriateCompare從最大的事情進行排序到最小,與是在位置1和最大的第二大元素將在位置0
+1,nth_element比partial_sort有更好的運行時間 – Naveen 2009-09-14 10:49:38
最優算法不應該需要超過1.5 * N - 2的比較。 (一旦我們確定它是O(n),N?2 * N比較前面的係數是不是最優的)。
因此,首先確定每對中的「贏家」和「輸家」 - 即0.5 * N的比較。
然後通過比較獲勝者來確定最大的元素 - 這是另一個0.5 * N - 1的比較。
然後通過比較其中最大元素來自其他所有對的獲勝者的對的失敗者來確定第二大元素 - 另一個0.5 * N-1比較。
總比較= 1.5 N - 2
未經測試,但有趣:
template <typename T, int n>
class top_n_functor : public unary_function<T, void>
{
void operator() (const T& x) {
auto f = lower_bound(values_.begin(), values_.end(), x);
if(values_.size() < n) {
values_.insert(f, x);
return;
}
if(values_.begin() == f)
return;
auto removed = values_.begin();
values_.splice(removed, values_, removed+1, f);
*removed = x;
}
std::list<T> values() {
return values_;
}
private:
std::list<T> values_;
};
int main()
{
int A[] = {1, 4, 2, 8, 5, 7};
const int N = sizeof(A)/sizeof(int);
auto vals = for_each(A, A + N, top_n_functor<int,2>()).values();
cout << "The top is " << vals.front()
<< " with second place being " << *(vals.begin()+1) << endl;
}
如果最大是第一要素,搜索第二大[最大+ 1,結束)。否則搜索[開始,最大)和[最大+ 1,結束),並取兩者中的最大值。當然,這有O(2n),所以它不是最優的。
如果您有隨機訪問迭代器,你可以做的是快速排序並和使用不斷優雅遞歸:
template< typename T >
std::pair<T,T> find_two_largest(const std::pair<T,T>& lhs, const std::pair<T,T>& rhs)
{
// implementation finding the two largest of the four values left as an exercise :)
}
template< typename RAIter >
std::pair< typename std::iterator_traits<RAIter>::value_type
, typename std::iterator_traits<RAIter>::value_type >
find_two_largest(RAIter begin, RAIter end)
{
const ptr_diff_t diff = end-begin;
if(diff < 2)
return std::make_pair(*begin, *begin);
if(diff < 3)
return std::make_pair(*begin, *begin+1);
const RAIter middle = begin + (diff)/2;
typedef std::pair< typename std::iterator_traits<RAIter>::value_type
, typename std::iterator_traits<RAIter>::value_type >
result_t;
const result_t left = find_two_largest(begin,middle);
const result_t right = find_two_largest(middle,end);
return find_two_largest(left,right);
}
這有O(n)和不應超過NomeN's implementation使更多的比較。
前k通常是有點大於n更好(日誌K)
template <class t,class ordering>
class TopK {
public:
typedef std::multiset<t,ordering,special_allocator> BEST_t;
BEST_t best;
const size_t K;
TopK(const size_t k)
: K(k){
}
const BEST_t& insert(const t& item){
if(best.size()<k){
best.insert(item);
return best;
}
//k items in multiset now
//and here is why its better - because if the distribution is random then
//this and comparison above are usually the comparisons that is done;
if(compare(*best.begin(),item){//item better than worst
erase(begin());//the worst
best.insert(item); //log k-1 average as only k-1 items in best
}
return best;
}
template <class it>
const BEST_t& insert(it i,const it last){
for(;i!=last;++i){
insert(*i);
}
return best;
}
};
當然的special_allocator
可以在本質上只是ķ多集value_types的陣列,並且(那些節點的列表,其典型地具有無因爲其他k正在multiset中使用,直到它的時間來放入一個新的,然後我們擦除然後立即重新使用它。好或者在std :: multiset和緩存中有內存alloc/free它是一個非常微小的工作,它可以在不違反STL分配器規則的情況下使其處於靜態狀態。但是對於固定的k<<n
,我會選擇GUESS(2n + delta * n),其中delta是小的 - 我的DEK ACP vol3 S & S被打包掉了,對delta的估計是我想做的更多工作。
平均最差的是我會猜測n(log(k-1)+ 2)時,以相反的順序和所有不同。
最好是2n + k(log k)k最好是第一個
- 1. 找到第二個和第三個最大元素數組java
- 2. 從給定範圍的向量中查找最大元素
- 3. 在已過濾的範圍內查找可見單元格的最大範圍
- 4. 在大小爲N的數組的每k個元素中查找最小元素和第二小元素
- 5. 在表中查找第二最大
- 6. 在最小和最大範圍表中查找值的位置
- 7. 最大範圍
- 8. 查找給定範圍內的大素數(〜8000位)
- 9. 查找範圍中包含的最大子樹的大小
- 10. 找到R中每行最大最大值和第二大最大值R
- 11. 查找指定日期範圍內的最大值
- 12. 查找平均值,最小值,最大值和範圍
- 13. 如何查找對象數組中的第二大元素
- 14. PSEUDO代碼和Python用於查找最大,第二大和最小號碼
- 15. Excel VBA根據相對範圍的最小值到最大值查找範圍內的單元格地址
- 16. 打印字符串中第一大和第二大元素
- 17. 查找表格中處於最小和最大範圍內的行
- 18. 查找本地最小和全局最大範圍內的所有數字
- 19. 在O(1)時間查找最大堆的第10個最大元素時間
- 20. 的Java查找最大元素
- 21. 查找元素的最大高度
- 22. 查找陣列中最大的元素
- 23. 查找最大元素的位置
- 24. 查找SQL中第N大元素
- 25. 查找數字「內」的最大素數
- 26. 在質數範圍內查找最大出現位數
- 27. 在動態範圍內查找局部最大值
- 28. 在二叉搜索樹中查找K個最大的元素
- 29. 查找二叉樹中的最大元素
- 30. 在swift中查找二維數組中的最大元素
簡單的代碼...你還能要求什麼?誠然,搜索不那麼「複雜」,但由於內存訪問的樂趣,幾乎肯定會變慢。 – Goz 2009-09-11 20:13:45
按定義排序的速度較慢,因爲您必須至少檢查O(n log n)次的元素。這保證只檢查元素O(n)次(當然n是#元素)。只有在相同列表上重複操作時,排序才能更有效。 – NomeN 2009-09-11 20:52:36
這是我最終實現的(應該可能在OP中提到過),但我正在尋找不同的東西(可能更快)。 – Jacob 2009-09-14 13:06:21