【问题标题】:Flatten n-dimensional vector展平 n 维向量
【发布时间】:2017-03-19 14:26:05
【问题描述】:

我制定了一种可以递归使用的算法,它以非递归方式工作,但是,我无法以递归形式对其进行测试,因为我无法从模板创建 n-1 维变量。
对于帮我写下变量名及其含义:

  • v:n维向量
  • dims:每个维度的 n 个长向量(例如:如果它是一个看起来像 int x[3][6][4] 的数组,那么 dims 看起来像:{3, 6, 4})
  • p:维度的乘积,用于得到平面向量的大小(例如:3*6*4)
  • ret: 返回的平面向量
  • sub_dims:与 dims 相同,但没有第一个维度(例如:{6, 4})
  • sub_p:与​​p 相同,但没有第一个因素(例如:6*4)
  • sub_ret: 返回的 n-1 维向量的平面向量

代码:

template <typename T>
vector<int> dim_flat(vector<T> v, vector<int> dims)
{
    // creating variables and vectors
    int n = dims.size();
    int p = dims[0];
    for (int i = 1; i < n; i++)
    {
        p *= dims[i];
    }
    int sub_p = p / dims[0];
    vector<int> sub_dims;
    sub_dims.assign(dims.begin() + 1, dims.end());
    vector<int> ret(p);

    // algorithm
    if (n > 1)
    {
        for (int i = 0; i < dims[0]; i++)
        {
            vector<int> sub_ret = dim_flat(v[i], sub_dims);

            for (int j = 0; j < sub_p; j++)
            {
                ret[i * sub_p + j] = sub_ret[j];
            }
        }
    }
    else
    {
        // case for the input is 1D 
        // not yet written
    }

    return ret;
}

使用此代码构建项目,但是如果我在 main 中调用它:

vector<int> ret = dim_flat(v, dims);

v 在哪里,例如一个 4D 向量,dims 是一个包含 {3, 3, 3, 3} 的向量,然后我在尝试构建时得到以下信息:

error C2784: 'std::vector<_Ty> dim_flat(std::vector<T>,std::vector<_Ty>)' : could not deduce template argument for 'std::vector<T>' from 'int'

换行

vector<int> sub_ret = dim_flat(v[i], sub_dims);

我有点(但不是真的)理解这个错误的含义,所以我预计会发生同样的情况,它为此做了:

T x = v[i];
vector<int> sub_ret = dim_flat(x, sub_dims);

这是我不再真正理解错误的部分,因为我认为使用参数vector&lt;T&gt; v 我指定了输入,例如4D 向量将被理解为T 的向量,其中T 是一个 3D 向量,它也可以被索引,因为它是一个vector&lt;T&gt;。所以按照这个逻辑,我认为如果我给递归第一个T是一个3D向量,那么这个3D向量现在将被理解为T'的向量,其中T'是一个2D向量,并且以此类推。

显然我的逻辑有缺陷,或者我使用了错误的方法(或两者兼而有之),所以问题是:我该如何解决/修复这个问题?

编辑:
感谢 Max66 的解决方案。
代码可能会更优化,但至少现在它可以工作了。
代码:

//// for integer only
// case input is 0-dimensional (simply a variable)
template <typename T>
vector<int> dim_flat (const T &v, const vector<int> &dims)
{
    return vector<int>(1, v);
}

// case input is n-dimensional
template <typename T>
vector<int> dim_flat(const vector<T> &v, const vector<int> &dims)
{
    // creating variables and vectors
    int n = dims.size();
    int p = dims[0];
    for (int i = 1; i < n; i++)
    {
        p *= dims[i];
    }
    int sub_p = p / dims[0];
    vector<int> sub_dims;
    sub_dims.assign(dims.begin() + 1, dims.end());
    vector<int> ret(p);

    // algorithm
    if (n > 1) // case n-dimensional
    {
        for (int i = 0; i < dims[0]; i++)
        {
            vector<int> sub_ret = dim_flat(v[i], sub_dims);
            for (int j = 0; j < sub_p; j++)
            {
                ret[i * sub_p + j] = sub_ret[j];
            }
        }
    }
    else // case 1-dimensional
    {
        for (int i = 0; i < p; i++)
        {
            vector<int> sub_ret = dim_flat(v[i], sub_dims);
            ret[i] = sub_ret[0];
        }
    }
    return ret;
}

【问题讨论】:

    标签: c++ templates vector


    【解决方案1】:

    简答:添加功能

    std::vector<int> dim_flat (int v, std::vector<int> const &)
     { return {v}; }
    

    如果你可以使用 C++11 或更新版本,或者

    std::vector<int> dim_flat (int v, std::vector<int> const &)
     { return std::vector<int>(1, v); }
    

    如果你必须使用 C++98

    长答案:如果我没记错的话,问题是,当你用std::vector&lt;int&gt; 调用dim_flat() 时(当Tint),你有n == 1,所以dim_flat()没有被调用(执行“输入一维的情况”)但是编译器不是很聪明地理解没有必要用int调用dim_flat()(而不是@ 987654331@) 所以寻找dim_flat(int, std::vector&lt;int&gt;) 并没有找到它。

    所以,为了让编译器满意,你必须实现dim_flat(int, std::vector&lt;int&gt;)

    可以是一个虚拟函数(返回一个空向量),但我建议你正确实现它。

    一点话题:请避免无用的向量副本;在您的dim_flat()vdims 中只读取,不修改;因此您可以将它们作为 const 参考接收,如下所示

    template <typename T>
    std::vector<int> dim_flat(std::vector<T> const   &  v,
                              std::vector<int> const &  dims)
    

    P.s.:你为什么不简单地写如下?

    std::vector<int> dim_flat (std::vector<int> const & v)
     { return v; }
    
    template <typename T>
    std::vector<int> dim_flat(std::vector<std::vector<T>> const & v)
     {
       std::vector<int>  ret;
    
       for ( auto const & e : v )
        {
          auto s = dim_flat(e);
    
          ret.reserve( ret.size() + s.size() );
          ret.insert( ret.end(), s.cbegin(), s.cend() );
        }
    
       return ret;
     }
    

    【讨论】:

    • 谢谢!通过最小的调整(而不是int v,我不得不使用T v),它可以工作。由于某种原因,用于返回的 C++11 格式不起作用,我得到了syntax error,但 C++98 格式有效。还要感谢您对 const 参考的建议。即使我知道它,并且确实想使用它,但我还是忘记放在那里。
    猜你喜欢
    • 2022-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-19
    • 2014-10-30
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    相关资源
    最近更新 更多