tags:

views:

81

answers:

4

I need to have a dynamic array, so I need to allocate the necessary amount of memory through a pointer. What makes me wonder about which is a good solution, is that C++ has the ability to do something like:

int * p = new int[6];

which allocates the necessary array. What I need is that, afterwards, I want to grow some parts of this array. A(n flawed) example:

int *p1 = &p[0];
int *p2 = &p[2];
int *p3 = &p[4];
// delete positions p[2], p[3]
delete [] p2;
// create new array
p2 = new int[4];

I don't know how to achieve this behavior.

EDIT: std::vector does not work for me since I need the time of insertion/deletion of k elements to be proportional to the number k and not to the number of elements stored in the std::vector.

Using pointers, in the general case, I would point to the start of any non continuous region of memory and I would keep account of how many elements it stores. Conceptually, I would fragment the large array into many small ones and not necessarily in continuous space in the memory (the deletion creates "holes" while the allocation does not necessarily "fill" them).

+8  A: 

You achieve this behavior by using std::vector:

std::vector<int> v(6);         // create a vector with six elements.
v.erase(v.begin() + 2);        // erase the element at v[2]
v.insert(v.begin() + 2, 4, 0); // insert four new elements starting at v[2]

Really, any time you want to use a dynamically allocated array, you should first consider using std::vector. It's not the solution to every problem, but along with the rest of the C++ standard library containers it is definitely the solution to most problems.

James McNellis
Let's say `k_1` the number of elements to insert, `k_2` the number of elements to delete and `n` the total number of elements in the vector with `k_1`, `k_2` << `n`. Does not the solution with `vector` takes `O(n)` instead of `O(k_1 + k_2)`?
myle
@myle: A removal from the middle of a `vector` takes time proportional to the number of elements in the vector that are after the range of elements being removed. An insertion in the middle may take time proportional to the total number of elements in the vector (if a reallocation is necessary). Since arrays are stored contiguously, there's no way around this. You would need to use another data structure (like a linked list) to get different performance characteristics (note, however, that in most real-world applications, a linked list is not the best choice of data structure).
James McNellis
If I could spare the memory fragmentation (which I can), if different pointers where pointing to the different "parts" of the array (as in the example) and `new` was allocating memory where it could do so, then I would have better performance, namely the `O(k_1 + k_2)`. I insist on this, since it is very crucial for my implementation.
myle
@myle: Well, a linked list gives you `O(k_1 + k_2)`; its just the rest of its performance characteristics that are generally a problem. Anyway, there is no container in the C++ standard library that does what you are looking for. If the performance of this particular use case is of utmost importance, you'll probably want to implement your own container. However, note that to get the best performance in this use case, you'll have to sacrifice performance of other, typically more frequent use cases (like forward iteration).
James McNellis
@myle: Then use a `list` with a custom allocator. But profile it, you might be surprised. The cache locality of the vector's buffer is often so superior to that of a list that modifications to the middle will be faster anyway.
GMan
[Also, to amend my first comment, you also have to add time proportional to the number of elements being inserted or removed, obviously.]
James McNellis
A new the data structure to be random accessible like in a `vector`. That is not true for a `list`, as far as I know. That is why I need (or feel that I need) pointers.
myle
@myle: No, a `list` does not support random access because random access in a linked list is slow. Random access in your proposed data structure (effectively a jagged array of arrays) would also be relatively inefficient (compared to access in an array).
James McNellis
Also, your proposed data structure would not give you `O(k_1 + k_2)` performance unless you know the locations of the insertions and removals ahead of time. At some point you are going to have to move elements around unless each element is independent like in a linked list.
James McNellis
You have replied satisfactorily to my question and it is not your problem that I didn't state well what I needed. Thanks for your effort. I really appreciate it.
myle
@myle: Sure, though if your problem still isn't solved, please do ask another question with the specific problem you are trying to solve ("I need a container that supports efficient random access and O(k) insertion and removal" or something like that).
James McNellis
I followed your suggestion. Thanks again. http://stackoverflow.com/questions/3809103/i-need-a-container-that-supports-efficient-random-access-and-ok-insertion-and-r
myle
+1  A: 

You should look into STL containers in C++, for example vector has pretty much the functionality you want.

schnaader
+1  A: 

I'd advise against doing this on your own. Look up std::vector for a reasonable starting point.

Jerry Coffin
+1  A: 

another option, besides std::vector is std::deque, which works in much the same way, but is a little more efficient at inserting chunks into the middle. If that's still not good enough for you, you might get some mileage using a collection of collections. You'll have to do a little bit more work getting random access to work (perhaps writing a class to wrap the whole thing.

TokenMacGuy
In the case of bulk insert/remove, at most n/2 copies occur, whereas with a vector, n copies may occur. the speedup is not major, but it is enough to be worthwhile.
TokenMacGuy
I retract my comment; you are indeed correct.
James McNellis
On the other hand, the speedup at insert comes at the cost of a similar, constant factor slowdown for random access. TANFL
TokenMacGuy