【问题标题】:Is there a better selection of datastructures and algorithms for this problem?对于这个问题,是否有更好的数据结构和算法选择?
【发布时间】:2019-11-05 18:39:33
【问题描述】:

对于以下问题,请提出更好的解决方案(就时间复杂性而言)。我的方法我最后已经解释过了。

有一个文件具有以下格式的记录:- RecordType;Symbol;price;id;parentId

示例文件看起来像 -

RecordType;Symbol;price;id;parentId

 - A;BANK_X;20;2345;0
 - A;BANK_Y;30;2346;0
 - A;BANK_Z;40;2347;0
 - M;BANK_X;50;2348;2345
 - M;BANK_Y;10;2349;2346 
 - A;BANK_X;20;2350;0 
 - A;BANK_E;40;2351;0 
 - M;BANK_X;45;2352;2345 
 - M;BANK_X;20;2353;2350

这样的文件包含数百万条记录。目标是编写一个高效的 C++ 程序,将文件拆分为多个文件,使得每个较小的文件包含 Y 条记录,其中 Y 是作为输入提供的整数。

要记住的要点:

  • 每条记录都有唯一的 ID(即记录中倒数第二个字段)
  • 对于匹配 A 和 M 记录的符号,应该在同一个较小的文件中。

例如,如果示例文件被拆分为至少包含 2 行的文件,则以下记录应在一个文件中:

 - A;BANK_X;20;2345;0
 - M;BANK_X;50;2348;2345
 - M;BANK_X;45;2352;2345

我解决问题的方法:

  1. 使用的数据结构:

    • 队列:这将包含对象,其中键将是 id(那些是父项),对象中的值将是一个包含子项列表的向量。
    • Unordered_map 1:键:id(即,记录在最后一个字段中值为 0 的 id),值:字符串(即从文件中读取的该 id 的记录)
    • Unordered_map 2: Key: id (即最后一个字段的记录值为 NON 0 的 ids), value: string (即从文件中读取的该 id 的记录)
  2. 算法:

    • 逐行读取文件
    • 解析记录的最后 2 个字段
    • 检查 id 是否为父项(即记录的最后一个字段是否为 0) 如是: create object{id, vactor} 放入队列 将 id 和字符串记录添加到 unordered_map 1 如果不: 在队列中搜索父id并在向量中添加子id(这可以做恒定时间搜索) 将id和字符串记录添加到unordered_map 2
    • 执行上述步骤直到文件结束。
    • 现在开始弹出队列并为每个 id(即父级)从 Unordered_map 1 中获取记录字符串写入一个新文件, 同样对于它的孩子(在向量中可用)从 Unordered_map 2 中获取记录字符串写入文件。 在这里,我将检查最小行数。
    • 根据 Y 的值,从 unsorted_map 中获取 id(父)和子的记录并写入新文件。

如果我考虑语句中提到的示例文件,在应用我的算法数据结构后将具有以下值:-

Queue< int, std::vector < int> >: [ {2345, <2348, 2352>}, {2346, <2349>}, {2347, <empty>}, {2350, <2353>}, {2351, <empty>}]
Unordered_map 1 < int, std::string >: [{2345, "A;BANK_X;20;2345;0"}, {2346, "A;BANK_Y;30;2346;0"}, {2347, "A;BANK_Z;40;2347;0"}, {2350, "A;BANK_X;20;2350;0"}, {2351, "A;BANK_E;40;2351;0"}]
Unordered_map 2 < int, std::string >: [{2348, "M;BANK_X;50;2348;2345"}, {2349, "M;BANK_Y;10;2349;2346"}, {2352, "M;BANK_X;45;2352;2345"}, {2353, "M;BANK_X;20;2353;2350"}]

【问题讨论】:

  • parent id 的作用是什么?父符号是否必须与其子符号在同一个文件中?
  • @fjardon:在任何记录中,如果父 ID 为 0,则表示该行的 ID 是父行。如果记录的父 id 不为零,则表示该行的 id 是子,并且它的父在同一行中由父 id 提及。子符号(即记录)应与父符号位于同一文件中。
  • 一个孩子可以成为另一个孩子的父母吗?
  • 不,一个孩子不能成为另一个孩子的父母。
  • 父母的子女人数有限制吗?

标签: c++ algorithm c++11 data-structures


【解决方案1】:

您的问题的以下陈述:

“这样的文件包含数百万条记录。”
“每条记录都有唯一的 id(即记录中倒数第二个字段)”

.. 断言我建议您使用 SQL 数据库。这样,您可以将所有内容保存在单个文件中以便于访问。您将来可以高效地select, insert, update, delete,而不会失去从第一天开始就获得的灵活性。

SQLite 确实是一个轻量级的替代品。

【讨论】:

  • @Abhishek SQLite 是一个 C 库。您可以将它包含到您的 C++ 程序中,有许多用于 SQLite 的“OO”C++ 包装器
【解决方案2】:

您可以使用矢量和地图来做到这一点。声明一个向量[SIZE_OF_SYMBLE]。用整数映射符号。然后每次获取条目时,首先从映射中获取符号的映射 int 值并将条目推送到该向量。

struct record{string recordType;char symbol;double price;int id;};
map<char,int> symbmol_to_int;
vector<record> piles[SIZE_OF_SYMBOL];

【讨论】:

    【解决方案3】:

    更新:

    我想出了一个更好的解决方案。由于看起来 id 是按排序顺序排列的,因此您可以在每行的处理之后立即写入文件。对于每个子记录,只需写入其父记录所在的文件。只需要记住你把父记录写入哪个文件即可。

    unordered_map<int, int> id_to_file_id;
    

    实际上,您不需要将整个字符串存储在地图中,您只需要存储它在哪一行。这将节省您使用的空间的一半。

    并使用这样的数据结构:

    unordered_map<int, int> id_to_line;
    map<int, vector<int>> groups; // map<parent_id, vector<child_id>>
    

    【讨论】:

    • 感谢 StillFantasy,但如果我存储行号,那么要获得实际行,我需要再次读取文件对吗?而这次我需要在随机位置读取文件(基于行号),是不是让我的程序太慢了?
    • 是的,我认为你是对的。我稍微改了一下。
    • @StillFantasy,挑战不是节省内存。挑战是为数百万条记录获得最有效的解决方案。您需要根据输入数字 Y 将文件拆分为多个文件。假设文件有 100 万条记录,前 1000 条记录仅供父母使用,之后的儿童记录(您永远不知道顺序)。 Y 的值为 10,你将如何在读取文件时拆分文件。即使您对孩子一无所知,也达到了第 1001 条记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多