【问题标题】:Quickly finding array element by pointer通过指针快速查找数组元素
【发布时间】:2021-08-04 00:16:41
【问题描述】:

我有一个字符串数组,其中每个字符串也可以通过分配给它的唯一指针清楚地识别。该数组中元素的顺序经常发生变化,例如由于排序。

我希望能够仅从其随附的指针中快速找到数组项的数字索引。例如,在下面的代码中对数组进行排序后,我希望0xfeedface 为 0,0xc0decafe 为 1,0xdeadbeef 为 2。当然,我不想遍历所有元素并手动比较指针值,因为这在现实生活中的应用程序中太慢了。那请问我该怎么做呢?

我需要一个仍然允许我使用std::sort 对项目进行排序的解决方案,而且我的目标平台上也没有 C++11,因此该解决方案不需要 C++11 或更高版本。感谢您的帮助!

#include <iostream>
#include <string>
#include <vector>
#include <array>

class RowItem
{
public:
   RowItem(std::string text, void *ptr) : m_text(text), m_ptr(ptr) {}
   std::string GetText() {return m_text;}
private:
   std::string m_text;
   void *m_ptr;
};
    
class RowCmp
{
public:
   RowCmp() {}
                    
   bool operator()(RowItem &first, RowItem &second) const
   {
    return first.GetText().compare(second.GetText()) < 0;   
   }
};

int main()
{   
    std::vector<RowItem> v;
    RowItem one("C\n", (void *) 0xdeadbeef), two("B\n", (void *) 0xc0decafe), three("A\n", (void *) 0xfeedface);
    
    v.push_back(one);
    v.push_back(two);
    v.push_back(three);
    
    std::sort(v.begin(), v.end(), RowCmp());                    
    
    for(size_t k = 0; k < v.size(); k++) std::cout << v[k].GetText();       

    return 0;
}

【问题讨论】:

  • 我需要一个仍然允许我使用 std::sort 的解决方案 -- 如果你保持矢量原样,并对指向的索引数组进行排序怎么办?代替物品?然后元素的顺序不会改变(即物理上,deadbeef 仍为 0,但在排序位置将位于index[0])。
  • 不管你喜不喜欢,在m_ptr 上没有点餐和/或在上述相同的地图上键入(因此订购是为了搭便车),你所说的," ...在现实生活中的应用程序中会太慢。” 是您唯一的选择。 必须按定义搜索等价的值的无序序列(它们是指针是不相关的)是 O(n) 退化算法。仅当包含容器按所述值排序(例如按 m_ptr 排序)或与原始容器共享内容(索引很好)的地图时,才能将您从冰冷的现实中解救出来。
  • @PaulMcKenzie:我不明白这有什么帮助,因为 AFAIU 我仍然需要遍历所有元素并比较指针值,不是吗?
  • @Andreas 你需要做的就是用向量中的指针和位置构建一个初始映射。无需进行线性搜索,因为您知道,例如,deadbeef 将位于index[map[deadbeef]] 的排序位置。问题是您需要额外的空间来存储地图和索引数组。想想数据库是如何做这些事情的。
  • @Andreas std::mapstd::unordered_map

标签: c++ arrays algorithm


【解决方案1】:

这是我在保罗在 cmets 的解释之后得出的。它似乎可以解决问题。正如保罗所建议的那样,它不对原始向量进行排序,而是保持原样。由于原始向量中的位置现在保持不变,我们可以使用一个简单的映射将指针值映射到相应的索引。

现在剩下要做的就是对引用原始向量中字符串的索引数组进行排序。完成之后,我们可以通过查看已排序的索引向量,使用其指针值轻松找到项目的新位置。

在代码中,它看起来像这样:

#include <iostream>
#include <string>
#include <vector>
#include <array>
#include <map>
#include <algorithm>

class RowItem
{
public:
   RowItem(std::string text, void *ptr) : m_text(text), m_ptr(ptr) {}
   std::string GetText() const {return m_text;} 
private:
   std::string m_text;
   void *m_ptr;
};

class RowCmp
{
public:
   RowCmp(std::vector<RowItem> &v) : m_v(v) {}
                    
   bool operator()(int first, int second) const
   {
    return m_v[first].GetText().compare(m_v[second].GetText()) < 0;     
   }
   
private:
   std::vector<RowItem> m_v;   
};

int main()
{   
    std::vector<RowItem> v;
    std::vector<int> index;
    RowItem one("C\n", (void *) 0xdeadbeef), two("B\n", (void *) 0xc0decafe), three("A\n", (void *) 0xfeedface);

    index.push_back(0);
    index.push_back(1);
    index.push_back(2);
    
    v.push_back(one);
    v.push_back(two);
    v.push_back(three);
    
    std::map<unsigned __int64, int> pmap;
    pmap[0xdeadbeef] = 0;    
    pmap[0xc0decafe] = 1;   
    pmap[0xfeedface] = 2;   
            
    std::sort(index.begin(), index.end(), RowCmp(v));                   
    
    for(size_t k = 0; k < v.size(); k++) std::cout << v[index[k]].GetText();        

    std::cout << "Deadbeef at: " << index[pmap[0xdeadbeef]] << "\n";
    std::cout << "Codecafe at: " << index[pmap[0xc0decafe]] << "\n";
    std::cout << "Feedface at: " << index[pmap[0xfeedface]] << "\n";
                
    return 0;
}

【讨论】:

  • 是的,这就是我的想法。一些小的改动——你应该有#include &lt;algorithm&gt;,并且用uint64_t替换unsigned __int64。一旦你这样做了,那么代码runs correctly。此外,您可以使用std::vector&lt;int&gt; index(3); 然后std::iota(index.begin(), index.end(), 0); 来初始化索引向量。另外我建议你解释一下你做了什么(基本上使用我的 cmets 作为指导),这样这看起来不像是一个纯代码的答案,而是一个其他人可以学习的答案。
  • 好的,我已经添加了一些解释。该代码确实在我的旧 Visual C++ 上编译时没有警告,所以我将任何对其他编译器的修改留给读者作为练习:)
  • 省略 &lt;algorithm&gt; 确实是一个错误——这就是声明 std::sort 的地方。此外,uint64_tC++11 的一部分,因此除非您使用的是旧标准,否则所有 C++11 标准编译器都支持它。
  • 好的,添加了&lt;algorithm&gt;。正如 OP 中提到的,我仍然使用一个非常旧的编译器,根本没有 C++11...
  • 好的,没问题。这可能就是您使用std::map 而不是std::unordered_map 的原因。
猜你喜欢
  • 1970-01-01
  • 2012-03-22
  • 2016-09-25
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
  • 1970-01-01
  • 2018-11-04
  • 2021-10-08
相关资源
最近更新 更多