所以我想说我有一个结构
struct largestOwners
{
string name;
double amountOwned;
};
我正在使用带有300个名字和数量的ifstream从文件中读取它。
如何在输入过程中跟踪最高的5个数字?所以我不必排序,而是在ifstream输入期间跟踪它。
我的目标是在输入过程中跟踪5个最高金额,以便以后轻松打印出来。并节省时间/处理而不是将来做
我知道我可以将它存储在一个数组或另一个结构中,但是在ifstream输入结构时有什么好的算法来跟踪它吗?
让我们说,当我正在阅读时,文本文件看起来像这样。
4025025 Tony
66636 John
25 Tom
23693296 Brady
363 Bradley
6200 Tim
谢谢!
答案 0 :(得分:4)
要跟踪传入数字流中最高的5个数字,可以使用大小为5的min-heap(C ++ STL set
可以用作最小堆)。
首先使用前5个数字填充min-heap。之后,对于每个传入元素,将其与最大的5个数字(最小堆的根)中的最小值进行比较。如果当前数字小于该值,则不执行任何操作,否则删除第5个最大值(从最小堆弹出)并将当前数字插入最小堆。
删除和插入最小堆将花费O(log n)时间。
例如,请考虑以下数字流:
1 2 5 6 3 4 0 10 3
最小堆最初会有1 2 3 5 6
。
遇到4
时,1会被删除,4会被插入。
最小堆现在看起来像这样:2 3 4 5 6
遇到0
时,没有任何反应。
遇到10
时,会删除2并插入10。
最小堆现在看起来像这样:3 4 5 6 10
遇到3
时,没有任何反应。
所以最后一组5个最大的元素都包含在堆(3 4 5 6 10
)
你甚至可以调整它以跟踪输入数字流中的k个最高元素。只需将最小堆的大小更改为k。
答案 1 :(得分:2)
在阅读文件时,请保留已查看的5个最大数字(及其所有者)的排序列表。 每当您读取的值高于5的最低值时,请删除最低值并在排序列表中插入新号码。
列表列表可以存储在数组中,也可以存储在任何其他具有订单的数据结构中,您可以在其中实现排序和插入。 (或者已经实施的地方)
除了对列表进行排序之外,您还可以在每次阅读新条目时简单地浏览5个条目(不应该太糟糕,因为5个条目的数量非常小)
答案 2 :(得分:1)
您可以使用标准库函数std::nth_element()
。
为结构实现比较函数(或重载比较运算符)应该相当容易。然后你只需将文件解析为那些文件的向量并完成它。该算法使用部分排序,平均线性时间。
以下是我在下面链接的文档网站上给出的示例:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
int main()
{
std::vector<int> v{5, 6, 4, 3, 2, 6, 7, 9, 3};
std::nth_element(v.begin(), v.begin() + v.size()/2, v.end());
std::cout << "The median is " << v[v.size()/2] << '\n';
std::nth_element(v.begin(), v.begin()+1, v.end(), std::greater<int>());
std::cout << "The second largest element is " << v[1] << '\n';
}
供参考:
出于好奇,我实施了一些方法:
#include <algorithm>
#include <functional>
#include <queue>
#include <set>
#include <vector>
std::vector<int> filter_nth_element(std::vector<int> v, int n) {
auto target = v.begin()+n;
std::nth_element(v.begin(), target, v.end(), std::greater<int>());
std::vector<int> result(v.begin(), target);
return result;
}
std::vector<int> filter_pqueue(std::vector<int> v, int n) {
std::vector<int> result;
std::priority_queue<int, std::vector<int>, std::greater<int>> q;
for (auto i: v) {
q.push(i);
if (q.size() > n) {
q.pop();
}
}
while (!q.empty()) {
result.push_back(q.top());
q.pop();
}
return result;
}
std::vector<int> filter_set(std::vector<int> v, int n) {
std::set<int> s;
for (auto i: v) {
s.insert(i);
if (s.size() > n) {
s.erase(s.begin());
}
}
return std::vector<int>(s.begin(), s.end());
}
std::vector<int> filter_deque(std::vector<int> v, int n) {
std::deque<int> q;
for (auto i: v) {
q.push_back(i);
if (q.size() > n) {
q.erase(std::min_element(q.begin(), q.end()));
}
}
return std::vector<int>(q.begin(), q.end());
}
std::vector<int> filter_vector(std::vector<int> v, int n) {
std::vector<int> q;
for (auto i: v) {
q.push_back(i);
if (q.size() > n) {
q.erase(std::min_element(q.begin(), q.end()));
}
}
return q;
}
我做了一些测试:
#include <random>
#include <iostream>
#include <chrono>
std::vector<int> filter_nth_element(std::vector<int> v, int n);
std::vector<int> filter_pqueue(std::vector<int> v, int n);
std::vector<int> filter_set(std::vector<int> v, int n);
std::vector<int> filter_deque(std::vector<int> v, int n);
std::vector<int> filter_vector(std::vector<int> v, int n);
struct stopclock {
typedef std::chrono::high_resolution_clock high_resolution_clock;
std::chrono::time_point<high_resolution_clock> start, end;
stopclock() : start(high_resolution_clock::now()) {}
~stopclock() {
using namespace std::chrono;
auto elapsed = high_resolution_clock::now() - start;
auto elapsed_ms = duration_cast<milliseconds>(elapsed);
std::cout << elapsed_ms.count() << " ";
}
};
int main() {
// randomly initialize input array
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dist;
std::vector<int> v(10000000);
for (auto &i: v)
i = dist(gen);
// run tests
for (std::vector<int>::size_type x = 5; x <= 100; x+=5) {
// keep this many values
std::cout << x << " ";
{
stopclock t;
auto result = filter_nth_element(v, x);
}
{
stopclock t;
auto result = filter_pqueue(v, x);
}
{
stopclock t;
auto result = filter_set(v, x);
}
{
stopclock t;
auto result = filter_deque(v, x);
}
{
stopclock t;
auto result = filter_vector(v, x);
}
std::cout << "\n";
}
}
我发现看到这些方法的相对性能非常有趣(用-O3编译 - 我想我必须考虑一下这些结果):
答案 3 :(得分:0)
二叉搜索树可能是此问题的合适数据结构。也许你可以在STL或Boost中找到合适的Tree类(尝试寻找)。否则,如果你坚持,只需使用结构。
结构就像那样:
struct tnode { /* the tree node: */
char *word; /* points to the text */
int count; /* number of occurrences */
struct tnode *left; /* left child */
struct tnode *right; /* right child */
};
摘自 C语言程序,第6.5章 - 自引用结构。只需根据您的需求进行调整。
尽管如此,我认为如果你想用C ++编程,请尝试创建一个Tree数据结构(类)或尝试使用现有的数据结构。
考虑到您只有300个条目,应该这样做。 理论上,当输入数据是 random 时,它应该是有效的。但这是理论,并没有真正发挥你的作用。我认为这是一个很好的解决方案。
答案 4 :(得分:0)
你可以使用5个元素的排序缓冲区,如果item高于缓冲区的最低项,则可以在每一步中使用,将项放入缓冲区并逐出
答案 5 :(得分:0)
使用let a = array(10) { arc4random_uniform(10) }
print(a) // [3, 7, 9, 4, 2, 3, 1, 5, 9, 7] (Your output may be different :-)
个元素
首先创建一个类
map
如果最大的大小是&lt; 5,那么你还没有读过五个元素。
class Data {
public:
std::string name;
int number;
};
typedef std::map< int, Data > DataItems;
DataItems largest;
否则 - 如果它大于最大的五个中的最小值,那么最大的五个已经改变。
if( largest.size() < 5 ) {
largest[ dt.number] = dt;
} else {
答案 6 :(得分:0)
您可以使用set
来跟踪最高值。如果您想跟踪非唯一号码,请改用multiset
:
vector<int> nums{10,11,12,1,2,3,4,5,6,7,8,9}; //example data
int k=5; // number of values to track
set<int> s; // this set will hold the result
for(auto a: nums)
{
if(s.size()<k)s.insert(a);
else if(a>*s.begin())
{
s.erase(s.begin());
s.insert(a);
}
}
当然,您必须为struct
提供自定义比较功能。