灵活的阵列(或建议另一种数据结构)

时间:2014-01-03 08:44:29

标签: c++ arrays data-structures

我需要以这样的方式配置一维数组,使其可以灵活地重新排列,如同每个下一个k元素推回所有元素n次,然后返回到之前的结构(带来已删除的元素)。以下是一个例子:

p[10]={        //this is a one-dimensional array
1, 2, 3, 4, 5
4, 5 ,6, 7, 8}


//push each 'row' 2 units back, every 5 elements.
//"Row" here refers to the next nth element, here 5.

<del>, <del>, 3, 4, 5
<del>, <del> ,6, 7, 8


//New structure
<reserved>, <reserved>, 3, 4, 5
<reserved>, <reserved>, 6, 7, 8

//This is how it should look like in terms of data relevance, 
//with the reserved spaces not shown.

    3, 4, 5
    6, 7, 8

现在p[0]应为3p[3]=6

最简单的方法是使用新元素创建一个新数组,但我需要保留旧数组并在同一个数组上重复执行这些操作,然后将其返回到原始结构。我认为可能有一种使用指针的方法,也许是指针数组,但我不完全确定。如果有一个数据结构让我这么容易,请指点我。

4 个答案:

答案 0 :(得分:4)

您可以使用vector来实现此目的。它有push_backpop_backinserterase和其他一些方法。 点击此处获取更多信息: http://www.cplusplus.com/reference/vector/vector/

vector<int> myArray;

for(int i=0;i<8;i++)
{
    myArray.push_back(i+1);//initialize
}

for(int i=0; i<8; i++)
{
    //do something for finding the first 2 of each 5, (you can use mod 5)
            myArray.erase(myvector.begin()+index) //removing
}

答案 1 :(得分:2)

您可以创建自己的类,它将代表您的数组并将按您的意愿工作。在内部,它可以具有所有元素的向量。以下代码中的内容。

您定制的数组:

#include <iostream>
#include <vector>

    class Container
{
public:
    Container(int* buf, int len);

    int operator[] (int i) { return buffer[validIndexes[i]]; }

    void pushRowsBack(int n, int rowLength);
    void restore();

    int size() { return validIndexes.size(); }

private:
    std::vector<int> buffer;
    std::vector<int> validIndexes;
};

构造函数实现(只是一个具有工作示例的示例):

Container::Container(int* buf, int len) 
    : buffer(buf, buf+len), 
    validIndexes(len, 0)
{
    for (int i = 0; i < len; ++i)
    {
        validIndexes[i] = i;
    }
}

pushBackRow()实现:

void Container::pushRowsBack(int n, int rowLength)
{
    int numRows = validIndexes.size() / (float)rowLength + 0.5;
    std::vector<int>::iterator it = validIndexes.begin();

    // go through all the rows
    for (int i = 0; i < numRows; ++i)
    {
        // erase the first n elements in the row
        for (int j = 0; j < n; ++j)
        {
            it = validIndexes.erase(it);
        }

        // advance iterator to the next row
        it += rowLength - n; 
    }
}

restore()实现:

void Container::restore()
{
    validIndexes.resize(buffer.size());
    for (int i = 0; i < validIndexes.size(); ++i)
    {
        validIndexes[i] = i;
    }
}

使用示例:

void main()
{
    int buffer[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };

    Container c(buffer, 13);

    c.pushRowsBack(2, 5);
    for (int i = 0; i < c.size(); ++i)
    {
        std::cout << c[i] << ", ";
    }
    std::cout << std::endl;

    c.restore();
    for (int i = 0; i < c.size(); ++i)
    {
        std::cout << c[i] << ", ";
    }
    std::cout << std::endl;
}

输入:

1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 
11, 12, 13

推回长度为5乘2元素的行后的输出:

3, 4, 5, 
8, 9, 10, 
13

恢复后的输出():

1, 2, 3, 4, 5, 
6, 7, 8, 9, 10, 
11, 12, 13

答案 2 :(得分:1)

您必须将数据封装到不像普通列表(即隐藏列)的类中。如果你只需要删除列,那么你可以这样做:(c ++ 11)

#include <initializer_list>

template <typename DataT, unsigned Rows, unsigned Cols>
class Table
{
public:
    Table(const std::initializer_list<DataT>& list) {
        int i = 0;
        for (const DataT& item : list)
            data[i++] = item;
    }
    void setFirstCol(unsigned v) { firstCol = v; }
    DataT& operator[] (unsigned i) {
        const unsigned c = Cols-firstCol;
        return data[i/c*Cols + i%c + firstCol];
    }
private:
    unsigned firstCol = 0;
    DataT data[Rows*Cols];
};

用法:

int main() {
    Table<int, 2, 5> table = {
        1, 2, 3, 4, 5,
        4, 5, 6, 7, 8
    };

    cout << table[0] << endl; // 1
    cout << table[5] << endl; // 4

    table.setFirstCol(2); // you can undo this with setFirstCol(0);

    cout << table[0] << endl; // 3
    cout << table[3] << endl; // 6
}

但是如果您要求删除任何元素,那么您必须将每个元素转换为包含元素本身的结构和已删除状态的标志:

template<DataT>
struct Element { // store this struct in your array
    DataT data;
    bool deleted;
};

你可以用类似的东西来回溯元素(注意线性复杂性):

DataT& operator[](unsigned i) {
    for (Element& e : list) {
        if (i == 0) return e;
        if (!e.deleted) --i;
    }
    throw std::out_of_range("index is out of the container");
}

我认为你有了这个主意。

答案 3 :(得分:0)

正如rozina所说:

#include <cassert>
#include <iostream>
#include <vector>

template <typename T>
class ArrayView
{
public:
    explicit ArrayView(const std::vector<T>& v) : v(&v) { assert(this->v->size() % 5 == 0); }

    const T& operator[] (std::size_t index) const {
        const std::size_t newIndex = getCorrectedIndex(index);

        return v->at(newIndex);
    }

    std::size_t size() const { return (v->size() / 5) * 3; }

private:
    std::size_t getCorrectedIndex(std::size_t index) const {
        return (index / 3) * 5 + (index % 3) + 2;
    }
private:
    const std::vector<T>* v;
};


int main(int argc, char* argv[]) {

    std::vector<int> v = {1, 2, 3, 4, 5,
                          4, 5, 6, 7, 8};
    ArrayView<int> a(v);

    for (std::size_t i = 0, size = a.size(); i != size; ++i) {
        std::cout << a[i] << " ";
        if ((1 +i) % 3 == 0) {
            std::cout << std::endl;
        }
    }
    return 0;
}

输出:

3 4 5
6 7 8