【问题标题】:What data structure should I use to model a database/table?我应该使用什么数据结构来建模数据库/表?
【发布时间】:2017-01-20 16:19:13
【问题描述】:

数据库通常是这样的

┃Name|Age|..┃
┠────┼───┼──┨
┃John│025│..┃
┃Carl│033│..┃
┃....│...│..┃

在这种情况下,我指的是具有固定列大小和可变大小的未排序行的表,这些行可以通过 id 来寻址。

C++11(或更早版本)中是否有数据结构可以表示这样的数据?

我想了几种方法来欺骗这样的结构,但没有一个是完美的。

1。单独std::vector

std::vector<std::string> name;
std::vector<unsigned int> age;

// Write
name.push_back("John");
age.push_back(25);

// Read
std::cout << "The first entry is (" << name[0] << " | " << age[0] << ")\n";

但是,定义一个包含许多列的表需要大量标记,并且通过在每个 std::vector 上调用 push_back 来写入它真的很乏味。

2。 std::vectorstd::tuple

(在这种情况下std::pair 就足够了)

std::vector<std::tuple<std::string, unsigned int>> table;

// Write
table.push_back(std::make_tuple("John", 25));

// Read 1
std::string name;
unsigned int age;
std::tie(name, age) = table[0];
std::cout << "The first entry is (" << name << " | " << age << ")\n";

// Read 2
enum
{
    NAME = 0,
    AGE
}
std::cout << "The first entry is (" << std::get<NAME>(table[0]) << " | "
<< std::get<AGE>(table[0]) << ")\n";

(对不起,如果我在这里搞砸了;我从昨天就知道std::tuple 的存在)

这很好,但是从它读取需要大量标记,这一次,当您必须定义要放入值的新变量时。您可以对任何您需要的变量执行 std::tie值,但这变得不可读。第二种方法几乎完美,但在 C++11 中我不想使用隐式枚举。

3。 std::vectorstd::array

enum
{
    NAME = 0,
    AGE
}

std::vector<std::array<std::string, 2> table;

// Write
table.push_back({"John", "25"});

// Read
std::cout << "The first entry is (" << table[0][NAME] << " | " << table[0][AGE] << ")\n";

这也很不错,但它遇到了与 2.2 相同的问题。这也只允许std::string 值。不过,作为交换,它提供了更短更好的语法。

【问题讨论】:

  • std::list&lt;row&gt; 其中row 是一个类,表示您要存储在每一行中的数据。其实这取决于你的要求。
  • 大多数数据库使用经典的B-Tree data structure
  • 数据结构与算法相关联。需要谈论您将要对数据库做什么 以确定您应该如何存储它。甚至规模也很重要;具有 10 PB 数据的“数据库”将使用不同于具有 10 KB 数据的结构。哪些操作需要快速?按名称查找?按年龄查询?按名称将一张桌子连接到另一张桌子怎么样?线程是一个问题吗?数据列是硬类型还是软类型?读取和写入有多常见?等等等等。
  • 您可能对Boost MultiIndex感兴趣
  • 我必须以某种方式将其加载到内存中

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


【解决方案1】:

我建议使用std::vector&lt;Record&gt; 来保存您的记录。

使用std::map&lt;key, vector_index&gt; 作为记录的索引。这将使您能够通过不同的搜索条件访问记录,而无需一直对向量进行排序。

【讨论】:

  • 为什么不直接std::map&lt;key, Record&gt;
  • @kim366:您的建议将对给定键进行优化搜索,但如果需要使用不同的键查找记录,则速度会较慢。使用向量,所有记录都在一个位置。可以针对不同的搜索条件使用多个地图。请参阅数据库理论 - 索引表。
【解决方案2】:

您没有考虑过的一件事是使用某种关联数组的std::vector,即std::mapstd::unordered_map

这将允许您使用数据库列名检查向量(或其他顺序容器)中的给定项目

item["Name"]
item["Age"]

等等。显然,您必须使用变体或类似boost::any 的值。

如果您希望在 C++ 中与数据库通信,并在编译时知道列的类型(正如您从建议中看到的那样),那么可能值得考虑直接从数据库架构。关于这个主题已经有几个问题herehere。如果db值为null怎么办?

【讨论】:

  • 但是std::map 只允许两个值
  • @kim366 这些值是用于检索存储在数据类型中的数据的键,该数据类型本身可能是一种可以包含多种数据的类型,正如 Doctorlove 在答案中解释的那样。
  • Map 允许 很多 个值,每个键对应一个。并且 vlaue 可能是另一张地图 - 如果您使用正确的类型。
【解决方案3】:
#-------------------------------------------
#Try with this piece of code based on <map>
#-------------------------------------------    
#include <iostream>
#include <map>
using namespace std;
//---
class myBook
{
public:
    string ISBN;
    string Title;
    int Pages;

    myBook();
    myBook(const myBook &);
    ~myBook(){};
    myBook &operator=(const myBook &pTr);
    int operator==(const myBook &pTr) const;
    int operator<(const myBook &pTr) const;
};

myBook::myBook()
{
    ISBN = "";
    Title = "";
    Pages = 0;
}


myBook::myBook(const myBook &copyin)
{
    ISBN = copyin.ISBN;
    Title = copyin.Title;
    Pages = copyin.Pages;
}


ostream &operator<<(ostream &output, const myBook &myBook)
{
    output << myBook.ISBN << ':' << myBook.Title << ':' << myBook.Pages << std::endl;
    return(output);
}


myBook& myBook::operator=(const myBook &pTr)
{
    this->ISBN = pTr.ISBN;
    this->Title = pTr.Title;
    this->Pages = pTr.Pages;
    return(*this);
}


int myBook::operator==(const myBook &pTr) const
{
    if( this->ISBN != pTr.ISBN) return(0);
    if( this->Title != pTr.Title) return(0);
    if( this->Pages != pTr.Pages) return(0);
    return(1);
   }

//---------------------------
main()
{
    map<string, myBook> BooksLibrary;
    myBook book1;
    //---
    book1.ISBN="1243954-23";
    book1.Title="Autobiography by Ben Franklin";
    book1.Pages=432;
    BooksLibrary["0001"] = book1;
    //---
    book1.ISBN="555-USA991";
    book1.Title="I Robot by Isac Asimov";
    book1.Pages=323;
    BooksLibrary["0002"] = book1;
    //---
    for( map<string, myBook>::iterator ii=BooksLibrary.begin();     ii!=BooksLibrary.end(); ii++)
    {
        std::cout << (*ii).first << "|" << (*ii).second << endl;
    }
    //---
    return(0);
}

【讨论】:

    猜你喜欢
    • 2011-12-12
    • 2011-10-24
    • 1970-01-01
    • 2016-10-31
    • 1970-01-01
    • 1970-01-01
    • 2016-12-08
    • 1970-01-01
    相关资源
    最近更新 更多