与数组的虚拟串联

Virtual concatenation with arrays

本文关键字:虚拟 数组      更新时间:2023-10-16

假设我有3个双精度数组a1[]a2[]a3[],每个数组的长度分别为L1、L2、L3

假设我想"虚拟地"连接这些数组,也就是说,我想创建一个阵列a_virtual[],使得a_virtual = {a1[L1], a2[L2], a3[L3]}在逻辑上(尽管在物理上)这些阵列可能彼此不连续。

因此,如果我想访问a_virtual[5]L1=2L2=3L3=1,则会获取a3[0]。为了访问a_virtual[0],将提取a1[0]

我该怎么做这个

  • 在C中
  • 在C++中(如何用std::vectors代替数组)也很有用)
  • 在CUDA

我怀疑,如果有一种方法可以做到这一点,那么这三种环境都是一样的,但根据提供的功能。

以下是C中使用链表和(尾)递归的可能解决方案:

#include <stdio.h>
struct dblarr {
    double *data;
    size_t len;
    struct dblarr *next;
};
double *fetch(const struct dblarr *arr, size_t index) {
    if (arr == NULL) return NULL;
    if (index < arr->len) return arr->data + index;
    return fetch(arr->next, index - arr->len);
}
int main(void) {
    double a1[2] = {1, 2};
    double a2[3] = {1, 2, 3};
    double a3[1] = {1};
    struct dblarr x1, x2, x3;
    x1.data = a1; x1.len = sizeof a1 / sizeof *a1; x1.next = &x2;
    x2.data = a2; x2.len = sizeof a2 / sizeof *a2; x2.next = &x3;
    x3.data = a3; x3.len = sizeof a3 / sizeof *a3; x3.next = NULL;
    printf("before %fn", *fetch(&x1, 5));
    *fetch(&x1, 5) = 0.42;
    printf(" after %fn", *fetch(&x1, 5));
    return 0;
}

您可以在http://ideone.com/mY0ix.

下面的内容怎么样?它是非常硬编码的,不是最好/最干净的代码,但也许你可以概括这个逻辑?

#include <iostream>
#include <vector>
using namespace std;
void logicalConcat(vector<int>& a1, vector<int>& a2, vector<int>& a3, int k) {
    if(k > a1.size() - 1)
        k -= a1.size();
    else { 
        cout << a1[k] << endl;
        return;
    }
    if(k > a2.size() - 1)
        k -= a1.size();
    else {
        cout << a2[k] << endl;
        return;
    } 
    cout << a3[k] << endl;
}

这里的k是您想要的虚拟串联的索引。我们没有连接任何东西,只是在向量上迭代。

如果数组不需要连续,那么一种方法是将单个索引转换为两个索引,一个用于指向实际数组的指针数组,另一个用于具有所需元素的数组。

要做到这一点,您需要创建一个指向这些数组的指针数组:

double** arrays = {a1, a2, a3};

然后是它们长度的数组:

int arraysizes = { sizeof(a1) / sizeof(*a1), sizeof(a2) / sizeof(*a2), sizeof(a3) / sizeof(*a3) };

然后,给定一个索引n,您可以通过进行来计算arrays的两个索引

int i1 = 0, j = 0;
while (n - arraysizes[j] >= 0)
    n -= arraysizes[j++], ++i1;

然后,您可以像这样对指针数组进行索引,以获得实际元素:

arrays[n][i2]

您还可以创建一个包装器类来使用内置的operator[]执行此运算。

其他一些为基本的C实现提供了答案。

以下是一个类的通用c++实现的一些示例代码,该类在不复制任何数组元素的情况下创建虚拟级联数组。一旦创建,虚拟数组就可以像普通向量一样进行索引(读取或写入):

#include <vector>
#include <map>
#include <iostream>;
using namespace std;
class VirtualArray {
public:
    multimap<int,double*> startIndices;  // reverse map of starting index to its sub array
    int size;
    VirtualArray() : size(0) {}
    double & operator[](int i) {
        // find proper subarray in log(n) time
        multimap<int,double*>::iterator iter = --startIndices.upper_bound(i);
        double *subarray = iter->second;
        int startIndex = iter->first;
        // index into subarray
        return subarray[i-startIndex];
    }
    void addArray(double* array, int length) {
        startIndices.insert(make_pair(size, array));
        size += length;
    }
    void addVector(vector<double> & vec) {
        startIndices.insert(make_pair(size, vec.data()));
        size += vec.size();
    }
};
int main() {
    double a1[3], a2[4], a3[6] = {1, 2, 3, 4, 5, 6};
    int L1 = 3, L2 = 4, L3 = 6;
    vector<double> a3vec;
    a3vec.assign(a3,a3+6);
    VirtualArray vArray;
    vArray.addArray(a1,L1);
    vArray.addArray(a2,L2);
    vArray.addVector(a3vec);
    cout << vArray[10];
    return 0;
}