对于这个问题,是否有更好的数据结构和算法选择?

时间:2019-11-05 18:39:33

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

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

有一个文件,其记录具有以下格式:- 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记录的符号,应将其保存在同一较小文件中。

例如,如果将示例文件拆分为至少包含两行的文件,则以下记录应位于一个文件中:

 - 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),value:字符串(即从文件中读取该id的记录)
    • Unordered_map 2:键:id(即在最后一个字段中记录的记录为NON 0的ID),value:字符串(即从文件中读取的该ID的记录)
  2. 算法:

    • 逐行读取文件
    • 解析记录的后2个字段
    • 检查id是否为父级(即记录的最后一个字段是否为0) 如是: 创建对象{id,vactor }放入队列 将id和字符串记录添加到unordered_map 1 如果不: 在队列中搜索父ID,并在向量中添加子ID(可以进行恒定时间搜索) 将id和字符串记录添加到unordered_map 2
    • 执行上述步骤,直到文件结束。
    • 现在开始弹出队列,并为每个ID(即父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"}]

3 个答案:

答案 0 :(得分:1)

以下是您问题的陈述:

  

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

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

SQLite确实是一种轻量级的选择。

答案 1 :(得分:0)

您可以使用矢量和地图进行此操作。声明一个带有整数的vector [SIZE_OF_SYMBLE] .map符号。然后,每次获得一个条目时,首先从map中获取该符号的映射的int值,然后将条目推入该矢量。

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

答案 2 :(得分:0)

更新:

我想出了一个更好的解决方案。由于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>>