Values being overwritten in array of pointers - c++

I'm Java guy trying to solve discrete knapsack problem in c++. However, I'm having trouble with pointers. I have an object with a field
Item ** items;
representing array of items to choose from. I also created a method to add an item which works like insertion sort (at least I hope so).
void Knapsack::addItem(Item item) {
int k = itemCount - 1;
if (this->items[k] != NULL) {
return;
}
while (k > 0 && this->items[k - 1] == NULL) {
k--;
}
if (k == 0) {
this->items[0] = &item;
} else {
int i = 0;
while (i < k && item < *(this->items[i])) {
i++;
}
for (int n = k; n > i; n--) {
this->items[n] = this->items[n - 1];
}
this->items[i] = &item;
}
}
Later, in my main I invoke the method by
knapsack->addItem(*(new Item(values.at(0), values.at(1))));
values being a vector of ints. The method itself seems to work fine, however, debugger shows that everytime I invoke the method with new Item, the previous values already put in my array are set to the same values as the new item.
(ex. if items[0] has value of 5, and I invoke the method with an item valued as 10, the items[0] instantly is set to 10).
Why are the values overwritten? I am creating a new object everytime I invoke the method.
EDIT:
Problem was fixed by replacing
this->items[0] = &item;
this->items[i] = &item;
with
this->items[0] = new Item(item.getWeight(), item.getValue());
this->items[i] = new Item(item.getWeight(), item.getValue());
SECOND EDIT:
The answer shows better (and probably correct) way to do this. Now the function takes a pointer instead of an object.
void Knapsack::addItem(Item * item);
this->item[i] = item;
knapsack->addItem(new Item(values.at(0), values.at(1)));

You are storing a pointer to a temporary copy of an Item object in the array in your addItem function, once the function returns the temporary object will be destroyed and you will be left with an invalid pointer. Make sure to allocate an Item object on the heap and passing a pointer to your addItem function or just use a vector of type std::vector<Item> and save your objects in there.

Related

Maintaining a Min heap on deletion c++

Test case:
8,7,5,2,3,6,9 (NOT min heap) (this is element A* for buildHeap function)
2,3,5,7,8,6,9 (min heap after calling build heap)
3,5,6,7,8,9 (after calling deleteMin) THIS IS INCORRECT
it should be this 3,7,5,9,8,6
I can't seem to find the problem with deleteMin i know my heapify is working but idk maybe im not seeing something.
Element Heap::deleteMin(Heap& heap){
Element deleted = heap.H[0];
heap.H[0] = heap.H[heap.size-1];
heap.size--;
cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
for(int i=heap.capacity/2-1;i>=0;--i)
heapify(heap,i);
return deleted;
}
void Heap::heapify(Heap& heap,int index){
int smallest = 0;
int left = 2*index;
int right = 2*index+1;
if(left < heap.size && heap.H[left].getKey() < heap.H[index].getKey())
smallest=left;
else
smallest=index;
if(right < heap.size && heap.H[right].getKey() < heap.H[smallest].getKey())
smallest=right;
if(smallest != index){
int swapKey = heap.H[index].getKey();
heap.H[index].setKey(heap.H[smallest].getKey());
heap.H[smallest].setKey(swapKey);
heapify(heap,smallest);
}
}
void Heap::buildHeap(Heap& heap, Element* A){
for(int j=0;j<heap.capacity;++j){
heap.insert(heap,A[j]);
for(int i=heap.capacity/2-1;i>=0;--i)
heapify(heap,i);
}
}
The first problem is that your calculations for child indexes are wrong. If you're using H[0] as the root of the heap, then
left = (2*index)+1
right = (2*index)+2
The calculations you have assume that the root is at H[1].
The other problem is that you're doing too much work in your deleteMin function:
Element Heap::deleteMin(Heap& heap){
Element deleted = heap.H[0];
heap.H[0] = heap.H[heap.size-1];
heap.size--;
cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
for(int i=heap.capacity/2-1;i>=0;--i)
heapify(heap,i);
return deleted;
}
After you delete the minimum item and put the last item in the heap at the root, you just need to call heapify(heap, 0); There's no reason to re-build the entire heap in that loop.
So your function becomes:
Element Heap::deleteMin(Heap& heap){
Element deleted = heap.H[0];
heap.H[0] = heap.H[heap.size-1];
heap.size--;
cout<<deleted.getKey()<<" has been deleted from heap"<<endl;
heapify(heap, 0);
return deleted;
}
Your buildHeap method is similarly doing too much work.
You might be interested in a refresher on heaps. My blog article at http://blog.mischel.com/2013/09/29/a-better-way-to-do-it-the-heap/ explains their operation in very simple terms, and my simple heap of integers shows a bare-bones implementation. It's in C# rather than C++, but the code is very similar. You should be able to understand it without trouble.

I need to update a Vector of pointers in C++ in a unique way

So I have a vector of pointers to a class I defined. I have a function that takes the 0 index of the pointer and returns it. After that I need to remove the data in that index then take the item in the last index of the vector and put it into the 0 index. As of right now I am just setting the pointers to NULL if I return them, and then I pushback the final object in the vector and finally pop it back. I am not sure if this method is the best way of solving my issue. Here is my code though:
Instrument* loanOut() {
for (int i = 0, i < library.size(), i++) {
if (library[i] != NULL) {
return library[i];
}
else {
return NULL;
}
}
library[0] = NULL;
library.push_back(library[library.size()]);
}
Algorithmically, this is what you are describing :
Object PopFrontAndReplace(std::vector<Object>& objects) {
if (!objects.size()) {return Object();}
Object o = objects[0];
objects[0] = objects.back();
objects.pop_back();
return o;
}
Does that answer the question?

Deleting an element from an array of objects

I tried to write a function that gets an object ("Stone") and deletes the stone from a given array. code:
void Pile::del_stone(Stone &s)
{
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i <size;++i)
{
if (s != Pile_arr[i])//if the given object to delete is different from the current
{
temp[i] = Pile_arr[i];//copy to the new array
}
else
{
i--;
}
}
Pile_arr = temp;
set_size(this->size - 1);
temp = NULL;
delete[] temp;
}
Pile_arr is a member of Pile class.
The problem is that i get an infinite loop, because i decrease i. I cant figure out how to solve this issue. Any ideas?
Use two indexes: i and j. Use i to know which element of the original array you are looking and j to know where to put the element in temp.
You need to use a separate counter to track where new elements should be placed.
I have used n below:
Stone *temp = new Stone[size - 1];
int n = 0; // Stores the current size of temp array
for (int i = 0;i <size;++i) {
if (s != Pile_arr[i]) {
temp[n++] = Pile_arr[i];
}
}
It's also worth considering the case where s is not found in the array, as this would cause a runtime error (Attempting to add size elements to an array of size size - 1).
Using a STL container would be a far better option here.
This function will:
Allocate a new array of length size-1
Search for the intended object
If you find it, copy it to the same exact position in the array
If you don't --i
Finally, ++i
First of all, this function is bad for 3 reasons:
It only copies one item over--the given item. You have an array with only 1 object.
It copies the item from index to index. Since the final array is one smaller, if the object is at the max original index, it will be out of bounds for the new array.
If the object is not immediately found, the array will get stuck, as you decrease the index, and then increase it using the loop--you'll never move again.
Stone *temp = new Stone[size - 1];//allocate new array
for (int i = 0;i
Instead:
Cache the found object, then delete it from the original array or mark it. temp = found object
Copy the array, one by one, without copying empty spaces and closing the gap. Copy temp_array[i] and increment i if and only if temp_array[j] is not marked/deleted. Increment j
Decide where to put the found object.
Once again, you can decide to use separate indexes--one for parsing the original array, and one for filling the new array.

Creating dynamic collection error

I have this code for managing dynamic collection List, which is mostly inspired with .NET System.List collection, but this is written in normal C++.
void List<T>::Insert(int index, T item)
{
if(index > GetLength() && index >= 0)
throw new StandartException("Index was out of array range");
if(GetLength()==length)
{
T * newl = new T[length + 4];
this->CopyTo(newl);
delete[] this->items;
this->items = newl;
length += 4;
}
T * store = new T[length];
CopyTo(store, index);
store[index] = item;
CopyTo((store + index + 1), index, GetLength() - index);
used++;
delete[] items;
items = store;
}
template <typename T>
void List<T>::CopyTo(T * destination, int start, int count)
{
for(int i = start, c = 0;i < GetLength() && c < count;i++, c++)
*(destination + i) = items[i];
}
So there is method Insert, which has to insert item on specified index in array.
For first, I'm checking if is index specified between 0 and Length + 1 (because I need to have a option to add item on the ond of collection). Then I'm testing if it is not end of allocated array (GetLength() = gets number of elements in array, length = number of allocated space for elements). If it is, I'm allocating new space for array, copying actual elements, freeing old storage and setting pointer to new address.
After that I'm allocating new space again. I'm copying actual elements from zero to index - 1, setting item which has to be inserted on it's position and copying other old elements to thier indexes (their previous index + 1). On the end I'm freeing old space and adding new.
ERROR: I started debugging. Everything was normal, I've run Insert for first without problem, but on first deletion (delete[] this->items; in if block) I've received this error:
Does anybody know why am I getting this and how can I repair it? I think that I haven't gone throught array range anywhere.
Please help.
Your problem is this line:
T * store = new T[length];
You insert an item, but don't allocate an array that is any larger than before. When you go to CopyTo the new array, you overflow the array.

Copy elements of an old array of pointers into new array of pointers?

I need some assistance with a C++ project. What I have to do is remove the given element from an array of pointers. The technique taught to me is to create a new array with one less element and copy everything from the old array into the new one except for the specified element. After that I have to point the old array towards the new one.
Here's some code of what I have already:
I'm working with custom structs by the way...
Data **values = null; // values is initialized in my insert function so it is
// populated
int count; // this keeps track of values' length
bool remove(Data * x) {
Data **newArray = new Data *[count - 1];
for (int i = 0; i < count; i++) {
while (x != values[i]) {
newArray[i] = values[i];
}
count -= 1;
return true;
}
values = newArray;
return false;
}
So far the insert function works and outputs the populated array, but when I run remove all it does is make the array smaller, but doesn't remove the desired element. I'm using the 0th element every time as a control.
This is the output I've been getting:
count=3 values=[5,6,7] // initial insertion of 5, 6, 7
five is a member of collection? 0
count=3 values=[5,6] // removal of 0th element aka 5, but doesn't work
five is a member of collection? 0
count=4 values=[5,6,5] // re-insertion of 0th element (which is stored in
five is a member of collection? 0 // my v0 variable)
Could anyone nudge me in the right direction towards completing this?
First of all, your code is leaking memory like no good! Next you only copy the first element and not even that if the first element happens to be the one you want to remove. Also, when you return from your function, you haven't changed your internal state at all. You definitely want to do something along the lines of
Data** it = std::find(values, values + count, x);
if (it != values + count) {
std::copy(it + 1, values + count, it);
--count;
return true;
}
return false;
That said, if anybody taught you to implement something like std::vector<T> involving reallocations on every operation, it is time to change schools! Memory allocations are relatively expensive and you want to avoid them. That is, when implementing something like a std::vector<T> you, indeed, want to implement it like a std::vector<T>! That is you keep an internal buffer of potentially more element than there are and remember how many elements you are using. When inserting a new element, you only allocate a new array if there is no space in the current array (not doing so would easily result in quadratic complexity even when always adding elements at the end). When removing an element, you just move all the trailing objects one up and remember that there is one less object in the array.
Try this:
bool remove(Data * x)
{
bool found = false;
// See if x is in the array.
for (int i = 0; i < count; i++) {
if (x != values[i]) {
found = true;
break;
}
}
if (!found)
{
return false;
}
// Only need to create the array if the item to be removed is present
Data **newArray = new Data *[count - 1];
// Copy the content to the new array
int newIndex = 0;
for (int i = 0; i < count; i++)
{
if (x != values[i])
newArray[newIndex++] = values[i];
}
// Now change the pointers.
delete[] values;
count--;
values = newArray;
return true;
}
Note that there's an underlying assumption that if x is present in the array then it's there only once! The code will not work for multiple occurrences, that's left to you, seeing as how this is a school exercise.