custom list with for-each support c++ - c++

in start I want to apologize for my english. My problem is weird because I'm trying write own ArrayList looks and works like List in Java and I know it's like reinvent a wheel, but I do this for fun and for better understanding how it works. So every answer like "use STL", "use vector", "use something else but don't create own list" are not helpful.
So from start, I have own template to ArrayList with a few methods which are important for me. My ArrayList works as array where I use only a part of available space and if I need more space I create new bigger array and copy all old elements (I beleive that the way it works in Java ArrayList, tell me if I'm wrong). In array I store only pointers. And it is good template for save and remove known objects and if I only need read stored data, but real problem appear when I try write loop for read, check and remove specified element from list. I can not do this using standard for(int i=0;i
Supporting "for each" on custom const native C++ container class
supporting for each loop in classes
C++ for each in on custom collections
How to make the for each loop function in C++ work with a custom class
Creating my own Iterators
http://www.cprogramming.com/c++11/c++11-ranged-for-loop.html
So can someone explain me what I should write in my template to support for-each functionality. In many examples appear begin() and end() functions but no one explain why this name, what is a return type and why, and what this method should return. Here is my template code, if something is wrong, please tell me. I will use this code in my other apps because for me this implementation is more intuition than vector (I was definitely too long works with Java :))
template <class T> class ArrayList {
public:
ArrayList() {
array = new T*[1000];
arraySize = 1000;
n = 0;
};
void add(T &arg) { //add new element at end
if (n == arraySize) {
increase();
}
array[n] = &arg;
n++;
};
void addAt(T &arg, unsigned int pos) { //add new element at specific position and override
if (pos >= 0 && pos <= n) {
if (pos == n) {
add(arg);
}
else {
array[pos] = &arg;
}
}
else {
throw "IndexOutOfBoundException";
}
};
void addAfter(T &arg, unsigned int pos) { //add new element between specific posittion and next element
pos++;
if (pos >= 0 && pos <= n) {
if (n == arraySize) {
increase();
}
for (unsigned int i = n; i > pos; i--) {
array[i] = array[i - 1];
}
array[pos] = &arg;
n++;
}
else {
throw "IndexOutOfBoundException";
}
};
void addList(ArrayList &list) { //add 'list' at the end
if (list.n > 0) {
while (list.n + n > arraySize) {
increase();
}
for (int i = 0; i < list.n; i++) {
array[n] = list.array[i];
n++;
}
}
};
void addListAfter(ArrayList &list, unsigned int pos) { //put 'list' inside list, start from 'pos'
pos++;
if (list.n > 0 && pos >= 0 && pos < n) {
while (list.n + n > arraySize) {
increase();
}
int m = n - 1;
while (m >= pos && m >= 0) {
array[m + list.n] = array[m];
m--;
}
for (int i = 0; i < list.n; i++) {
array[pos + i] = list.array[i];
}
n += list.n;
}
else {
throw "IndexOutOfBoundException";
}
};
void addListAfter(ArrayList &list, T &arg) { //put 'list' inside list, start after T, if T not exist 'list' will be added at the end
addListAfter(list, getIndex(arg));
};
void remove(T &arg, bool all) { //remove selected element if all=true remove all instance of object otherwise remove only first
if (all) {
int copies = 0;
for (int index = 0; index < n; index++) {
if (array[index] == &arg) {
copies++;
}
else if (copies != 0) {
array[index - copies] = array[index];
}
}
n -= copies;
if (copies == 0) {
throw "ArgumentNotFoundException";
}
while (arraySize - n >= 1000) {
decrease();
}
}
else {
remove(getIndex(arg));
}
};
void remove(unsigned int pos) { //remove element from specific position
if (pos >= 0 && pos < n) {
for (int i = pos; i < n - 1; i++) {
array[i] = array[i + 1];
}
n--;
if (arraySize - n >= 1000) {
decrease();
}
}
else {
throw "IndexOutOfBoundException";
}
};
void removeCopy(T &arg) { //leaves only one instance of an object and remove all other
int copies = -1;
for (int index = 0; index < n; index++) {
if (array[index] == &arg) {
copies++;
}
else if (copies > 0) {
array[index - copies] = array[index];
}
}
n -= copies;
if (copies == -1) {
n--;
throw "ArgumentNotFoundException";
}
while (arraySize - n >= 1000) {
decrease();
}
};
void repair() { //leaves only single instance of each object
for (int i = 0; i < n; i++) {
removeCopy(*array[i]);
}
};
void clear() { //remove all object from list
for (int i = 0; i < n; i++) {
array[i] = NULL;
}
n = 0;
};
T* get(unsigned int pos) { //return object on selected position
if (pos >= 0 && pos < n) {
return array[pos];
}
else {
throw "IndexOutOfBoundException";
}
};
unsigned int getIndex(T &arg) { //return position of selected object
unsigned int index = 0;
while (&arg != array[index] && index < n) {
index++;
}
if (index == n) {
throw "ArgumentNotFoundException";
}
return index;
};
ArrayList getSubList(unsigned int first, unsigned int last, bool deepCopy) { //return new list contains 'deep copy'/'copy reference' of all elements from (include) first to (include) last. If deepCopy=true function return deep copy, otherwise return copy of reference.
if (first < last&&first >= 0 && last < n) {
ArrayList<T> ret;
for (unsigned int i = first; i <= last; i++) {
if (deepCopy) {
ret.add(*new T(*array[i]));
}
else {
ret.add(*array[i]);
}
}
return ret;
}
throw "IndexOutOfBoundException";
};
unsigned int size() { //return size of list
return n;
};
bool isEmpty() {
return n == 0;
};
T *begin() {
return &*array[0];
}
T *end() {
return &*array[n];
}
private:
unsigned int arraySize; //actual size of array
unsigned int n; //number of elements in array
T** array;
void increase() { //increase size of array about 1000
if (arraySize + 1000 <= LONG_MAX) {
T** newArray = new T*[arraySize + 1000];
for (unsigned int i = 0; i < arraySize; i++) {
newArray[i] = array[i];
}
delete[] array;
array = newArray;
arraySize += 1000;
}
else {
throw "ArraySizeOutOfBoundException";
}
};
void decrease() { //decrease size of array about 1000
if (arraySize - 1000 > 0) {
arraySize -= 1000;
T** newArray = new T*[arraySize];
for (unsigned int i = 0; i < arraySize; i++) {
newArray[i] = array[i];
}
delete[] array;
array = newArray;
}
else {
throw "ArraySizeOutOfBoundException";
}
};
};

Some of the answers you've posted give good explanations. begin and end return iterators into a container, with begin referring to the first element and end to the position one item past the last element. As for the names, they seem intuitive. I believe this iterator design was chosen as an abstraction over pointers which would have minimal runtime cost.
I'm sure you've seen this link in the answers you linked to, but you should refer to this page on range-based for-loops.
In any case, you seem to be confused about the elements of the array vs. iterators pointing to the elements. With:
T **begin() {
return &array[0];
}
T **end() {
return &array[n];
}
Your program will work with ranged-for. Your element type is T*, not T.

Related

push_back and insert do not work properly in my own vector class

So, here is the header file where I implemented my own vector class in a simple way.
The problem is that even though the code compiles, the member functions pushBack and insert both do not work properly.
I'd be really glad if anyone can figure out the problem in my code or find some ways how I can get this problem resolved.
#include <iostream>
#include <new>
using namespace std;
template <typename T>
class DiyVector
{
public:
DiyVector()
{
arr = new T[1];
arrSize = 0;
index = 0;
capacity = 1;
}
~DiyVector()
{
delete[] arr;
}
T& at(unsigned int index) const
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else
{
return arr[index];
}
}
unsigned int size() const
{
return arrSize;
}
void pushBack(const T& item)
{
if (arrSize == capacity)
{
arrTemp = new T[capacity += 1];
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
delete[] arr;
capacity++;
arr = arrTemp;
}
arr[arrSize] = item;
arrSize++;
}
void popBack()
{
if (arrSize == 0)
{
throw OutOfRange{};
}
else
{
arrSize--;
}
}
void erase(unsigned int index)
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else
{
arrTemp = new T[capacity -= 1];
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
delete[] arr;
capacity--;
arr = arrTemp;
}
}
void insert(unsigned int index, const T& item)
{
if (index >= arrSize || index < 0)
{
throw OutOfRange{};
}
else if (index == capacity)
{
pushBack(item);
}
else if (0 <= index && index <= size())
{
arr[index] = item;
}
}
class OutOfRange{};
private:
unsigned int arrSize;
unsigned int capacity;
unsigned int index;
T* arr;
T* arrTemp;
};
For starters this check in some member functions (for example including insert)
if (index >= arrSize || index < 0)
^^^^^^^^^^
does not make sense because the variable index declared as having the type unsigned int never can be negative. So you may exclude the second sub-condition of the if statement.
In the function pushBack in this loop
for (unsigned int i = 0; i < capacity; ++i)
{
arrTemp[i] = arr[i];
}
subsritute capacity for arrSize.
Also remove the statement
capacity++;
because capacity was already incremented in this statement
arrTemp = new T[capacity += 1];
Within the function insert change this code snippet
else if (index == capacity)
{
pushBack(item);
}
else if (0 <= index && index <= size())
{
arr[index] = item;
}
to
if ( arrSize <= index )
{
pushBack(item);
}
else
{
arr[index] = item;
}
And you may remove the data member
unsigned int index;
because it is not used.
Pay attention to that the member function erase is also incorrect. At least there is no need to reallocate the array and change its capacity. And again there are twice capacity is decremented.
arrTemp = new T[capacity -= 1];
//...
capacity--;
that is the function has the same defects as the function pushBack. And in the loop you are coping the erased element.

Vector implemention in C++

Im trying to implement one of the Vector's Functions which is Resize
As much as I know all the other functions that I implemented are alright
In the test code I tried to print out every possible situation that might happen but when I came to print the size of the new Vector (poitner to integer called _elements)
I get an error "#.exr Triggered a breakpoint
for some odd reason in the tester (main) when i set at the loop "i <8" it works fine but if I do <= it triggers it
I believe the is caused by the resize function but Even after following the debugger I cant seem to find the problem
(explenation of the funtion is in the code)
the vector that I created was successfuly intelized for those who might wonder
Why is this happening?
the function with the following inputs / outputs are:
Vector::Vector(const Vector& other)
{
_elements = new int;
_size = other._size;
_capacity = other._capacity;
_resizeFactor = other._resizeFactor;
for (int i = 0; i < _size; ++i)
{
_elements[i] = other._elements[i];
}
}
//change _size to n, unless n is greater than the vector's capacity
//same as above, if new elements added their value is val
void Vector::resize(int n, const int& val)
{
if (n <= _capacity)
{
while (n < _size)
{
pop_back();
}
while (n > _size)
{
push_back(val);
}
_capacity = n;
}
else if (n > _capacity)
{
reserve(n);
while (n > _size)
{
push_back(val);
}
}
}
//change the capacity
void Vector::reserve(int n)
{
if (n > _capacity)
{
int size = _resizeFactor;
while (n - _capacity > size)
{
size = size + _resizeFactor;
}
_capacity += size;
}
}
//adds element at the end of the vector
void Vector::push_back(const int& val)
{
if (_size < _capacity)
{
_elements[_size] = val;
_size++;
}
else if (_size == _capacity)
{
int* a = new int[_capacity + _resizeFactor];
for (int i = 0; i < _size; i++)
{
a[i] = _elements[i];
}
_capacity += _resizeFactor;
_elements = new int[_capacity];
for (int i = 0; i < _size; i++)
{
_elements[i] = a[i];
}
delete a;
_elements[_size] = val;
_size++;
}
}
void Vector::pop_back()
{
if (_size > 0)
{
_elements[_size] = NULL;
_size--;
}
}
and I check it with
void print(const Vector& p)
{
cout << "Size = " << p.size() << ", Capacity = " << p.capacity() << ", isEmpty = " << (p.empty() ? "True" : "False") << endl;
}
and in main:
Vector a(10);
for (int i = 0; i <= 8; i++)
a.push_back(i+1);
print(a);
a.push_back(10);
print(a);
a.push_back(11);
print(a);
int x = 99;
a.resize(a.capacity() + 11, x);
print(a);

ArrayStack size

I had this task in C++ where I had to implement a Stack only using arrays (and not using things like Vectors). The teacher gave us an interface to follow and some code to test our ArrayStack on. My problem is that when I create a stack, fill it with 100 elements then empty it the size is 4 (i set 4 for a minimum) and when the teacher code do the same (in the testStack function) the same check fails.
Heres my code:
#include <iostream>
#include <string>
#include <assert.h>
using namespace std;
template<typename T>
class Stack {
public:
// Adds new element to the top of the stack
virtual void push(T x) = 0;
// Returns the top element AND removes it from the stack
// If the stack is empty use 'throw std::out_of_range("<human_friendly_message>");'
virtual T pop() = 0;
// Returns the top element but does NOT remove it from the stack
// If the stack is empty use 'throw std::out_of_range("<human_friendly_message>");'
virtual T top() = 0;
// Returns the current number of elements in the stack
virtual int getSize() = 0;
// Returns the current capacity of the underlying data storage (array)
virtual int getCapacity() = 0;
// Returns true if the stack has no elements and false otherwise
virtual bool isEmpty() = 0;
};
template<typename T>
class ArrayStack : public Stack<T>{
private:
T* data;
int arraysize;
int N;
void resize(int capacity)
{
T* copy = new T[capacity];
for (int i = 0; i < N; i++)
copy[i] = data[i];
T* p = data;
data = copy;
delete [] p;
}
public:
ArrayStack(){
N = 0;
data = new T[4];
arraysize = 4;
}
ArrayStack(int n){
if (n < 1) n = 1;
N = 0;
data = new T[n];
arraysize = n;
}
bool isEmpty(){ return N == 0; }
void push(T x)
{
if (N == arraysize)
{
resize(2 * arraysize);
arraysize *= 2;
}
data[N] = x;
N++;
}
T pop()
{
if (isEmpty()){
throw out_of_range("Can't pop on empty stack");
}
else{
N--;
T k;
k = data[N];
if (N > 0 && N == arraysize / 4 && arraysize/2>=4)
{
resize(arraysize / 2);
arraysize /= 2;
}
return k;
}
}
T top()
{
if (isEmpty()) throw out_of_range("Can't top on empty stack");
return data[N - 1];
}
int getCapacity()
{
return arraysize;
}
int getSize()
{
return N;
}
~ArrayStack()
{
delete [] data;
}
};
template<class T>
void testStack(Stack<T> *& stack, int cap = 128) {
for (int i = 0; i < 100; i++) {
stack->push(i);
assert(stack->top() == i);
}
assert(stack->getCapacity() == cap);
assert(stack->getSize() == 100);
for (int i = 99; i >= 0; i--) {
assert(stack->top() == i);
stack->pop();
}
assert(stack->getCapacity() == 4);
assert(stack->isEmpty());
}
int main() {
try {
Stack<int> * stackI = new ArrayStack<int>();
testStack(stackI);
delete stackI;
Stack<float> * stackF = new ArrayStack<float>(1);
testStack(stackF);
delete stackF;
Stack<double> * stackD = new ArrayStack<double>(65536);
testStack(stackD, 65536);
delete stackD;
Stack<string> * stackS = new ArrayStack<string>();
stackS->push("string1");
stackS->push("string2");
stackS->push("string3");
stackS->push("string4");
for (int i = 0; i < 4; i++) {
stackS->pop();
}
assert(stackS->isEmpty());
cout << "All tests passed!" << endl;
}
catch (std::exception & ex) {
cout << ex.what() << endl;
}
return 0;
}
As you may have noticed, the problem occurs with the last stack, the one with an initial capacity of 65536.
If you print the capacity just before the failed assertion, you will notice that it's 65536.
It looks like the stack hasn't been resized at all.
Looking at your conditions for when to shrink the storage, there is a required condition that N == arraysize / 4.
Since N doesn't become greater than 100, and 65536 / 4 is 16384, this condition will never be true.
Replacing == with <= takes care of it:
N <= arraysize / 4

Inserting value into sorted array without duplicates: C++

For this program I have three data files. The first has a list of numbers, the second is a list of numbers with an add (A) or delete (D) command. I have to put the numbers from the first file into the third file, then update the final file based on the commands and numbers in the second file. The third file cant have duplicates and must be sorted while values are being inserted. Here are the functions I have, I'm having difficulty getting the items stored into the array without duplicates. The array must be statically sized, I did a #define of max size 2000 which is more than enough to handle the numbers I need. Thanks so much! If I should upload the main let me know, but I'm fairly certain the problem lies in one of these functions.
int search(int value, int list[], int n) // returns index, n is logical size of array
{
int index = -1;
for(int i = 0; i < n; i++)
{
if(value == list[i])
{
index = i;
return index;
}
}
return index;
}
void storeValue(int value, int list[], int& n)
{
int i = n;
for(; i > 0 && list[i - 1] < value; i--)
{
list[i] = list[i - 1];
}
list[i] = value;
n++;
}
void deleteValue(int loc, int list[], int n)
{
if(loc >= 0 && loc < n)
{
for(int i = loc; i < n - 1; i++)
list[i] = list[i +1];
n--;
}
}
UPDATE: Now duplicates are being stored, but only for some numbers.
For example: my 3rd file is: 1,2,8,8,9,101,101,104,etc.
The output should be: 1,2,8,9,101,104,etc
value: value to be inserted
list[]: array being modified (must be static)
n: logical size of array
I can't figure out why some numbers are duplicated and others aren't
In my main, I run the search function and if a -1 is returned (the value isn't already found) then I run the storeValue function.
Here are my updated functions:
int search(int value, int list[], int n) // returns index
{
int index = -1;
for(int i = 0; i < n; i++)
{
if(value == list[i])
{
index = i;
return index;
}
}
return index;
}
void storeValue(int value, int list[], int& n)
{
int i = n;
for(; i > 0 && list[i - 1] > value; i--)
{
list[i] = list[i - 1];
}
list[i] = value;
n++;
}
void deleteValue(int loc, int list[], int& n)
{
if(loc >= 0 && loc < n)
{
for(int i = loc; i < n; i++)
{
if (i == loc)
{
list[i] = list[i + 1];
i++;
}
}
n--;
}
}
In your deleteValue function, you are deleting the value, but will end up with a duplicate because you are just reassigning the current index to the next value. For example, if you have the array:
char array[3] = [1, 2, 3];
and you wanted to delete the second integer, your function currently would output this:
[1, 3, 3]
What you want to do is make a new array and loop through your entire list, making sure to leave out the last element like so:
char* deleteValue(int loc, int list[], int n)
{
char* newArray[n - 1];
if (loc >= 0 && loc < n)
{
for (int i = 0; i < n - 1; i++)
{
if (i == loc) // You have arrived at the element that needs to be deleted
{
newArray[i] = list[i + 1];
i++; // So we skip over the deleted element
}
else
newArray[i] = list[i];
}
}
return newArray;
}
And this should take care of the case where the last value is duplicated.

Algorithm that builds heap

I am trying to implement build_max_heap function that creates the heap( as it is written in Cormen's "introduction do algorithms" ). But I am getting strange error and i could not localize it. My program successfully give random numbers to table, show them but after build_max_heap() I am getting strange numbers, that are probably because somewhere my program reached something out of the table, but I can not find this error. I will be glad for any help.
For example I get the table:
0 13 18 0 22 15 24 19 5 23
And my output is:
24 7 5844920 5 22 15 18 19 0 23
My code:
#include <iostream>
#include <ctime>
#include <stdlib.h>
const int n = 12; // the length of my table, i will onyl use indexes 1...n-1
struct heap
{
int *tab;
int heap_size;
};
void complete_with_random(heap &heap2)
{
srand(time(NULL));
for (int i = 1; i <= heap2.heap_size; i++)
{
heap2.tab[i] = rand() % 25;
}
heap2.tab[0] = 0;
}
void show(heap &heap2)
{
for (int i = 1; i < heap2.heap_size; i++)
{
std::cout << heap2.tab[i] << " ";
}
}
int parent(int i)
{
return i / 2;
}
int left(int i)
{
return 2 * i;
}
int right(int i)
{
return 2 * i + 1;
}
void max_heapify(heap &heap2, int i)
{
if (i >= heap2.heap_size || i == 0)
{
return;
}
int l = left(i);
int r = right(i);
int largest;
if (l <= heap2.heap_size || heap2.tab[l] > heap2.tab[i])
{
largest = l;
}
else
{
largest = i;
}
if (r <= heap2.heap_size || heap2.tab[r] > heap2.tab[i])
{
largest = r;
}
if (largest != i)
{
std::swap(heap2.tab[i], heap2.tab[largest]);
max_heapify(heap2, largest);
}
}
void build_max_heap(heap &heap2)
{
for (int i = heap2.heap_size / 2; i >= 1; i--)
{
max_heapify(heap2, i);
}
}
int main()
{
heap heap1;
heap1.tab = new int[n];
heap1.heap_size = n - 1;
complete_with_random(heap1);
show(heap1);
std::cout << std::endl;
build_max_heap(heap1);
show(heap1);
}
Indeed, the table is accessed with out-of-bounds indexes.
if (l <= heap2.heap_size || heap2.tab[l] > heap2.tab[i])
^^
I think you meant && in this condition.
The same for the next branch with r.
In case you're still having problems, below is my own implementation that you might use for reference. It was also based on Cormen et al. book, so it's using more or less the same terminology. It may have arbitrary types for the actual container, the comparison and the swap functions. It provides a public queue-like interface, including key incrementing.
Because it's part of a larger software collection, it's using a few entities that are not defined here, but I hope the algorithms are still clear. CHECK is only an assertion mechanism, you can ignore it. You may also ignore the swap member and just use std::swap.
Some parts of the code are using 1-based offsets, others 0-based, and conversion is necessary. The comments above each method indicate this.
template <
typename T,
typename ARRAY = array <T>,
typename COMP = fun::lt,
typename SWAP = fun::swap
>
class binary_heap_base
{
protected:
ARRAY a;
size_t heap_size;
SWAP swap_def;
SWAP* swap;
// 1-based
size_t parent(const size_t n) { return n / 2; }
size_t left (const size_t n) { return n * 2; }
size_t right (const size_t n) { return n * 2 + 1; }
// 1-based
void heapify(const size_t n = 1)
{
T& x = a[n - 1];
size_t l = left(n);
size_t r = right(n);
size_t select =
(l <= heap_size && COMP()(x, a[l - 1])) ?
l : n;
if (r <= heap_size && COMP()(a[select - 1], a[r - 1]))
select = r;
if (select != n)
{
(*swap)(x, a[select - 1]);
heapify(select);
}
}
// 1-based
void build()
{
heap_size = a.length();
for (size_t n = heap_size / 2; n > 0; n--)
heapify(n);
}
// 1-based
size_t advance(const size_t k)
{
size_t n = k;
while (n > 1)
{
size_t pn = parent(n);
T& p = a[pn - 1];
T& x = a[n - 1];
if (!COMP()(p, x)) break;
(*swap)(p, x);
n = pn;
}
return n;
}
public:
binary_heap_base() { init(); set_swap(); }
binary_heap_base(SWAP& s) { init(); set_swap(s); }
binary_heap_base(const ARRAY& a) { init(a); set_swap(); }
binary_heap_base(const ARRAY& a, SWAP& s) { init(a); set_swap(s); }
void init() { a.init(); build(); }
void init(const ARRAY& a) { this->a = a; build(); }
void set_swap() { swap = &swap_def; }
void set_swap(SWAP& s) { swap = &s; }
bool empty() { return heap_size == 0; }
size_t size() { return heap_size; }
size_t length() { return heap_size; }
void reserve(const size_t len) { a.reserve(len); }
const T& top()
{
CHECK (heap_size != 0, eshape());
return a[0];
}
T pop()
{
CHECK (heap_size != 0, eshape());
T x = a[0];
(*swap)(a[0], a[heap_size - 1]);
heap_size--;
heapify();
return x;
}
// 0-based
size_t up(size_t n, const T& x)
{
CHECK (n < heap_size, erange());
CHECK (!COMP()(x, a[n]), ecomp());
a[n] = x;
return advance(n + 1) - 1;
}
// 0-based
size_t push(const T& x)
{
if (heap_size == a.length())
a.push_back(x);
else
a[heap_size] = x;
return advance(++heap_size) - 1;
}
};