Suppose you have an array, items, with capacity 5 and suppose also you have a count varaible that counts each entry added to the array. How would you realloacte the array? Using C++ syntax?
void BST::reallocate()
{
item *new_array = new item[size*2];
for ( int array_index = 0; array_index < size * 2; array_index++ )
{
if ( ! items[array_index].empty )
{
new_array[array_index].theData = items[array_index].theData;
new_array[array_index].empty = false;
}
}
maxSize += size;
delete [] items;
items = NULL;
items = new_array;
}
How do you reallocate an array?
BST ctor is below with the private items struct, just to eliminate any confusion.
BST::BST(int capacity) : items(new item[capacity]), Position(0),
leftChild(0), rightChild(0), maxSize(capacity)
{
}
this is in the BST header:
private:
int size;
int maxSize;
int Position;
int leftChild;
int rightChild;
struct item
{
bool empty;
data theData;
};
item *items;
The quesetion is that i seem to be having a hard time with the reallocation of my items array.
I would reallocate it in the form of a std::vector<item>, assuming that there is no overriding reason to use an array. That would avoid several problems completely.
Why are you doing this at all? Why do you think that:
std::vector<item> items;
won't work for you?
Your old array items has only size elements, so you need to change the upper limit in your for loop to size from size*2 when you're copying the old elements to the new array.
Maybe because size is not initialized. Also, you would need to make sure size is less than maxSize.
Related
Inside the ArrayList I'm trying to delete all possible 0's that are appended as input, but for now it only deletes just one 0, no matter where it is located. But seems like I can't delete more than one zero at the time. How can I fix this?
void AList::elimZeros(){
int i;
int curr = 0;
for(i=0; i < listSize; i++) {
if ( (listArray[i] != 0 ) && (curr<listSize) ){
listArray[curr] = listArray[i];
curr++;
}
else if (listArray[i] == 0 )
{
listArray[curr] = listArray[i+1];
listSize--;
curr++;
}
}
}
This is the class for the ADT
class AList : public List {
private:
ListItemType* listArray; // Array holding list elements
static const int DEFAULT_SIZE = 10; // Default size
int maxSize; // Maximum size of list
int listSize; // Current # of list items
int curr; // Position of current element
// Duplicates the size of the array pointed to by listArray
// and update the value of maxSize.
void resize();
public:
// Constructors
// Create a new list object with maximum size "size"
AList(int size = DEFAULT_SIZE) : listSize(0), curr(0) {
maxSize = size;
listArray = new ListItemType[size]; // Create listArray
}
~AList(); // destructor to remove array
This is the input I'm testing with:
int main() {
AList L(10);
AList L2(20);
L.append(10);
expect(L.to_string()=="<|10>");
L.append(20);
expect(L.to_string()=="<|10,20>");
L.append(30);
L.append(0);
L.append(40);
L.append(0);
L.append(0);
expect(L.to_string()=="<|10,20,30,0,40>");
L.elimZeros();
expect(L.to_string()=="<|10,20,30,40>");
assertionReport();
}
It'd be helpful if you posted the class code for AList. Think you confused Java's ArrayList type, but assuming you're using vectors you can always just do:
for (int i = 0; i < listSize; i++) {
if(listArray[i] == 0) listArray.erase(i);
}
EDIT: Assuming this is the template of for the AList class, then there is simply a remove() function. In terms of your code, there are two issues.
You reference listSize in the for loop, then decrement it inside of the loop. Each iteration evaluates the value separately so you're reducing the number of total loop iterations and stopping early.
The other thing is if the entry is zero you shouldn't increment curr and set listArray[curr] = listArray[i+1]. This is basically assuming the next entry will not be a zero. So if it is, then you're copying the element and moving to the next. Your if statement can be cleaned up with:
if (listArray[i] == 0) {
listSize--;
} else {
listArray[curr] = listArray[i];
curr++;
}
I am working on an assignment that involves me writing a template class for a queue. It uses a dynamically allocated array. I am having trouble with the copying of the array. This is the prompt.
aQueue.setCapacity(newCapacity), that changes the capacity of aQueue to newCapacity. (This is much trickier than Stack::setCapacity(): if newCapacity is zero or < getSize(), setCapacity() should throw an exception; otherwise, it should allocate a new array with the new capacity, copy the values from the old array into the new array, and deallocate the old array.) To help you see all the things that can go wrong, you should make certain your method passes all the tests in this test method before working on the rest of the project.
Instance variables are:
unsigned mySize; // number of items I contain
unsigned myCapacity; // how many items I can store
unsigned myFirst; // index of oldest item (if any)
unsigned myLast; // index of next available spot for append (if any)
Item* myArray; // dynamic array of items
This is what I have so far:
template <class Item>
void ArrayQueue<Item>::setCapacity(unsigned newCapacity) {
if (newCapacity == 0 || newCapacity < mySize) {
throw QueueException("setCapacity()","newCapacity is too small");
} else {
Item * newArray = new Item[newCapacity];
unsigned y = myFirst;
for (unsigned x = 0; x < mySize; x++) {
newArray[y] = myArray[x];
y++;
}
delete [] myArray;
myArray = newArray;
myCapacity = newCapacity;
myLast = y;
}
}
These are the methods for getFirst() and getLast():
// Method returns first Item in ArrayQueue
template <class Item>
unsigned ArrayQueue<Item>::getFirst() const {
if (this->isEmpty()) {
throw EmptyQueueException("getFirst()");
} else {
return myArray[myFirst];
}
}
// Method returns last Item in ArrayQueue
template <class Item>
unsigned ArrayQueue<Item>::getLast() const {
if (this->isEmpty()) {
throw EmptyQueueException("getLast()");
} else {
return myArray[(myLast - 1 + myCapacity) % myCapacity];
}
}
I have been working on this for hours so any help would be greatly appreciated.
Credit goes to: Aconcagua
for (unsigned x = 0; x < mySize; x++) {
newArray[x] = myArray[(y % myCapacity)];
y++;
}
delete [] myArray;
myArray = newArray;
myCapacity = newCapacity;
myFirst = 0;
myLast = mySize;
By setting myFirst to 0 and myLast to mySize this properly allocates the indexes correctly. In addition to this when copying the array you most set newArray[x] to myArray[(y % myCapacity)].
Here's my code:
template<class T> class Test
{
public:
int Size = 0;
int Length = 0;
T* Items;
Test() {}
~Test()
{
delete [] Items;
}
void Append(const T& newItem)
{
if (Size + 1 >= Length)
{
Length += 250;
T* old = Items;
Items = new T[Length + 250];
for (int i = 0; i < Size; i++)
Items[i] = old[i];
delete [] old;
}
Items[Size] = newItem;
Size++;
}
};
Test<int> test;
for (int i = 0; i < 500000; i++)
test.Append(i);
I'm populating the dynamic array with 500000 integers which must take just 1-2Mb but it takes about 30Mb. There's no problem if i set the initial size to 500000(i.e. no resizing occurring). The grow value(250) seems to affect the memory somehow, if it's larger(for example 1000) then the memory usage is pretty low. What's wrong?
Typically, when you are reallocating an array, you do not want to modify the actual array until the very last second (to maintain exception safety):
T* temp = new T[new_size];
// assume count is the previous size and count < new_size
std::copy(Items, Items + count, temp);
std::swap(temp, Items);
delete [] temp;
Aside from that, there is nothing visible in your code that would cause a memory leak.
The extra size can possibly be due to other optimizations (being turned off) and/or debugging symbols being turned on. What compiler options are you using (and what compiler)? It should be noted that extra size is not necessarily an indication of a memory leak. Have you run this in a debugger or memory profiler which found a leak?
It should also be noted that std::vector does all of this for you.
Looking at your code, you're going to segfault more so than leak memory due to the fact that calling delete or delete[] on a non-NULL, but previously deallocated, pointer is a Bad Thing. Also, I don't believe this is your real code, because what you posted won't compile.
When you delete a pointer, always set it to NULL afterwards. It's good practice to initialize to NULL as well. Let's fix up your code to make sure we don't call delete on previously deallocated pointers. Also, let's initialize our pointer to NULL.
Your misuse of memory probably stems from the following lines of code:
Length += 250;
T* old = Items;
Items = new T[Length + 250];
Notice that you increment Length by 250, but then allocate Length+250 more elements? Let's fix that, too.
template<class T>
class Test
{
public:
int Size;
int Length;
T* Items;
Test() : Size(0), Length(0), Items(NULL){}
~Test() {
if (Items != NULL)
delete [] Items;
}
void Append(const T& newItem)
{
if (Size + 1 >= Length)
{
Length += 250;
T* old = Items;
Items = new T[Length];
for (int i = 0; i < Size; i++)
Items[i] = old[i];
delete [] old;
old = NULL;
}
Items[Size] = newItem;
Size++;
}
};
int main(){
Test<int> test;
for (int i = 0; i < 500000; i++)
test.Append(i);
}
I'd like to make a tree which can have some childrens in every node, but i don't know number of them. Tree have to be coded in small memory using (no extra data) with constant time to every node. I tought that i will make class Tree with value and children property (value is int, and children is stack) and array of pointers to every node in that Tree. My problem is to make this array. How can i make it with no extra data (std::vector sometimes allocate more memory than it needs) and constant time to every cell?
Everything's ok, but i also need constant time to every node. I know how many nodes will be, but i dont know how to make array of every node. It should work something like:
array[n];
A_Node *array[0]= new A_Node(16);
A_Node *n = new A_Node(1);
array[0]->addChild(n);
array[1]=n;
Or:
*(array+1)=n;
This is a possible example. It is not a full example solution but I hope you get the point. The point is that you can have a double pointer to nodes, which is basically an array of pointers to nodes of the tree.
Then you can reallocate the size yourself and to however much you want whenever there is a need to. But std::vector already does that for you so there is no real reason not to use it unless you want to control everything yourself or experiment, or are writing something in C. In any case hope this helps.
#include <stdio.h>
#include <stdlib.h>
// The initial buffer length of a node's children
#define BUFFER_LENGTH 5
// How much to multiply with if an addition of a child goes over the buffer
#define MULTIPLIER 2
///Your node class
class A_Node
{
public:
A_Node(int value,unsigned int childrenN=0)
{
this->value = value;
this->childrenN = childrenN;
//allocate BUFFER_LENGTH children for the node at first or childrenN if the childrenN is not initially 0
if(childrenN != 0)
{
this->children = (A_Node**) malloc(sizeof(A_Node*)*childrenN);
this->bufferLength = childrenN;
}
else
{
this->children = (A_Node**) malloc(sizeof(A_Node*)*BUFFER_LENGTH);
this->bufferLength =BUFFER_LENGTH;
}
}
//in the destructor of a node it would need some special care
~A_Node()
{
//for every child call the destructor of each child
for(int i = 0; i < this->childrenN; i++)
{
delete this->children[i];
}
//and only then free the buffer of the pointers to the children
free(this->children);
}
//adds a child
void addChild(A_Node* child)
{
//reallocate if needed
if(childrenN >= this->bufferLength)
{
realloc(this->children,sizeof(A_Node*)*MULTIPLIER);
}
this->children[childrenN] = child;
this->childrenN++;
}
A_Node* getChild(unsigned int i)
{
if(i >= this->childrenN)
{
return 0;
}
return this->children[i];
}
void printValue()
{
printf("%d\n",this->value);
}
private:
int value;
unsigned int childrenN;
A_Node** children;
unsigned int bufferLength;
};
///Your tree class
class A_Tree
{
public:
//constructor
A_Tree(int rootValue)
{
root = new A_Node(rootValue);
}
//destructor
~A_Tree()
{
//recursively kills all the nodes due to the destructor of node
delete root;
}
//your root node
A_Node* root;
};
int main()
{
A_Tree tree(16);
tree.root->addChild(new A_Node(42));
tree.root->printValue();
(tree.root->getChild(0))->printValue();
return 0;
}
Just keep track of the memory yourself rather than using a vector:
class Node {
public:
// In the constructor, initialize your array of children to NULL
// and the size of your children array to zero
Node() : mChildren(NULL), mSize(0) {}
void AddChild(Node* newChild) {
// allocate space for your new array
Node** newArray = new Node*[mSize + 1];
// copy over nodes from old array to new array
for (int i = 0; i < mSize; i++) {
newArray[i] = mChildren[i];
}
// add in our new child to the end of the array
newArray[mSize++] = newChild;
// if there was an old array (null check) free the memory
if (mChildren) {
delete [] mChildren;
}
// set our children array equal to our new array
mChildren = newArray;
}
Node* AccessChild(size_t index) {
// make sure it's a valid index and then return
assert(index < mSize);
return mChildren[index];
}
private:
Node** mChildren;
int mSize;
};
This will have no extra space for extra nodes, but it will require the size of an int in order to keep track of how many nodes you are storing. I don't see any way you could do it without this or having a constant number of children.
Please note, vectors double in size each time they need to reallocate because this is more efficient. While the solution above will be more efficient memory-wise, it will hurt a lot performance wise because it will require an allocation for every child addition, which is going to take O(N) allocations to add N nodes.
The performance of a vector will be O(log(N)) allocations to add N nodes, but again this solution sounds like it has the memory efficiency you're looking for.
Attempting to write a constructor for LinkedList to be initialised with an array of integers.
The program would call linked(array); which will add all the values within the array in to a linkedlist.
LinkedList::LinkedList(int array[])
{
headPtr->setData(array[0]); //setData method stores the integer at position 0 inside headPtr
Node *currentPtr = headPtr;
for (int i = 0; i < array.length(); ++i) //for loop to add the integers to the next node
{
currentPtr->setNext(new Node(array[i])); //creates a new node with the integer value of array position i
}
}
the trouble is the array.length (coming from Java) and I don't think the array length can be obtained this way?
I would suggest you to use iterator idiom, and make the constructor a templated constructor as:
class LinkedList
{
//...
public:
template<typename FwdIterator>
LinkedList(FwdIterator begin, FwdIterator end)
{
for (;begin != end; ++begin)
{
//treat begin as pointer, and *begin as dereferenced object
}
}
//...
};
And then you can use it as:
int arr[] = {1,2,3,4,5,6,7,8,9,10};
LinkedList lnklist(arr, arr+10);
Not only that. If you've std::vector<int>, then you can also use it to construct the linked list, as:
std::vector<int> v;
//..
LinkedList lnklist(v.begin(), v.end());
So using iterator idiom gives you this much power and flexibility. :-)
As Nawaz explained, going with iterator solution is better. But if you want to go with array ( static one though), then compiler can automatically deduce the size for you.
template<size_t size>
LinkedList::LinkedList(int (&array)[size])
{
headPtr->setData(array[0]); //setData method stores the integer at position 0 inside headPtr
Node *currentPtr = headPtr;
for (int i = 0; i < size++i) //for loop to add the integers to the next node
{
currentPtr->setNext(new Node(array[i])); //creates a new node with the integer value of array position i
}
}
Can be called as shown below.
int arr[] = {1,2,3,4,5,6,7,8,9,10};
LinkedList lnklist(arr);
Like others have said, it is not only important but vital that you get a good introductory C++ book and read it from front to back, simultaneously trying to forget what you know about Java while in C++ mode. They are not remotely similar.
Now to your problem, it can be solved by using std::vector and using its size method:
// put this with the other includes for your file
#include <vector>
LinkedList::LinkedList(const std::vector<int>& array)
{
headPtr->setData(array[0]); //setData method stores the integer at position 0 inside headPtr
Node *currentPtr = headPtr;
for (int i = 0; i < array.size(); ++i) //for loop to add the integers to the next node
{
currentPtr->setNext(new Node(array[i])); //creates a new node with the integer value of array position i
}
}
If you don't want to use vector, you have to pass in the size of the array to the function:
LinkedList::LinkedList(int array[], int arrlen)
{
headPtr->setData(array[0]); //setData method stores the integer at position 0 inside headPtr
Node *currentPtr = headPtr;
for (int i = 0; i < arrlen; ++i) //for loop to add the integers to the next node
{
currentPtr->setNext(new Node(array[i])); //creates a new node with the integer value of array position i
}
}
But it is recommended to use the vector version.