Below are my .cpp file and .h file. After getting a lot of help from Mike, I finally get it working; however, when I compile it on Visual Studio 2012, it gives me 2 warnings about '<' signed/unsigned mismatch right on the line "for (int i = 0; i < s.length(); i++)". Can anyone tell me what I did wrong in there ?
[code]
#include"DownwardStack.h"
#include<iostream>
#include<string>
#include<memory>
#include<cassert>
using namespace std;
unique_ptr<string> reverse_string(string const &s);
int main()
{
int count = 0;
string s;
unique_ptr<string> reverse(new string());
unique_ptr<DownwardStack<int>> ptr(new DownwardStack<int>());
cout << "Your string: ";
cin >> s;
reverse = reverse_string(s);
cout << "Your reverse string is: " << *reverse << endl;
if(ptr->IsEmpty())
cout << "ptr is empty" << endl;
else
cout << "ptr is not empty" << endl;
assert(ptr->IsEmpty());
assert(!ptr->IsFull());
ptr->Push(5);
ptr->Push(7);
ptr->Push(10);
ptr->Push(15);
ptr->Push(4);
cout << "Stack size: " << ptr->GetSize() << endl;
cout << "Top element: " << ptr->Peek() << endl;
cout << "Pop one element out." << endl;
ptr->Pop();
cout << "Top element: " << ptr->Peek() << endl;
return 0;
}
unique_ptr<string> reverse_string(string const &s)
{
DownwardStack<char> stack;
cout << s.length() << endl;
// Here it gives me a warning on the for loop
for (int i = 0; i < s.length(); i++)
{
stack.Push(s[i]);
}
unique_ptr<string> result(new string);
// Again it gives me a warning on the for loop
for(int i = 0; i < s.length(); i++)
{
*result += stack.Peek();
stack.Pop();
}
return result;
}
[/code]
This is my header file .h
[code]
#pragma once
#include<cassert>
#include<stack>
#include<string>
// size: number of elements inside the array
const int FIXED_ARRAYED_STACK_CAPACITY = 100;
template<class T>
class DownwardStack
{
public:
DownwardStack();
~DownwardStack();
// 1 step
// O(0)
int GetSize() const {return size;}
bool IsEmpty() const {return (size==0);}
bool IsFull() const {return (size==FIXED_ARRAYED_STACK_CAPACITY);}
T Peek();
void Pop();
void Push(T val);
void Clear();
void DisplayStack();
private:
int size;
T elements[FIXED_ARRAYED_STACK_CAPACITY];
};
// O(1)
template<class T>
DownwardStack<T>::DownwardStack()
{
size = 0;
}
template<class T>
DownwardStack<T>::~DownwardStack()
{
}
// assert = 1 step
// IsEmpty() = 1 step
// total = 2 steps
// f(n) = 2
// O(1)
template<class T>
T DownwardStack<T>::Peek()
{
assert(!IsEmpty());
return elements[FIXED_ARRAYED_STACK_CAPACITY - size];
}
// In order to take something out, it must not be empty
// assert = 1 step
// IsEmpty() = 1 step
// size-- = 1 step
// total = 3 steps
// O(1)
template<class T>
void DownwardStack<T>::Pop()
{
assert(!IsEmpty());
size--;
}
// In order to put in something, the stack must not be full
// assert = 1 step
// IsFull = 1 step
// assignment = 1 step
// size++ = 1 step
// total = 4 steps
// O(1)
template<class T>
void DownwardStack<T>::Push(T val)
{
assert(!IsFull());
elements[FIXED_ARRAYED_STACK_CAPACITY - size - 1] = val;
size++;
}
template<class T>
void DownwardStack<T>::Clear()
{
size = FIXED_ARRAYED_STACK_CAPACITY;
assert(IsEmpty());
}
[/code]
I would implement this as
std::string reverse_string(std::string const & s) {
return {s.rbegin(), s.rend()}; // C++11 or later
return std::string(s.rbegin(), s.rend()); // historical dialects of C++
}
If you really must make life difficult for yourself by using a stack: push each character into it, then pop each out into the new string. By the nature of stacks, you'll pop the characters in the reverse order.
std::string reverse_string(std::string const & s) {
DownwardStack<char> stack;
// write a loop to push each character of "s" onto "stack"
std::string result;
// write a loop to pop each character from "stack" into "result"
return result;
}
If you absolutely have to return a unique pointer, (which you really, really shouldn't), then that becomes
std::unique_ptr<std::string> reverse_string(std::string const & s) {
DownwardStack<char> stack;
// write a loop to push each character of "s" onto "stack"
std::unique_ptr<std::string> result(new std::string);
// write a loop to pop each character from "stack" into "*result"
return result;
}
And do the world a favour: only use new when you actually need it. There's no reason to use unique_ptr either for the stack (make that automatic), or the return value (since std::string is movable).
Related
The error pointed out was at the end just before the };
I don't even see any function overloading or any mismatching parameters.
This is simply a queue data structure that I was trying to implement. But unfortunately, I got these compiler errors. I am sharing the whole code so that easily one can help, since neither I have any function overloaded, not even the constructor nor I have used mismatched parameter. I guess image will help out to see the error.
template<class T>
class Queue {
private:
T* box;
int front;
int rear;
int number_Of_Elements;
int capacity;
public:
Queue(int cap = 0) {
capacity = cap;
front = rear = 0;
number_Of_Elements = 0;
}
bool Empty() {
return size == 0;
}
int next(int i) {
return ((i + 1) % capacity);
}
int previous(int i) {
return ((i + (capacity - 1)) % capacity);
}
int get_Number_Of_Elements() {
return number_Of_Elements;
}
void double_Box() {
T* temp = new T[capacity * 2];
for (int i = 0; i < size; i++) {
temp[i] = box[i];
}
front = 0;
rear = number_Of_Elements;
delete[] box;
box = temp;
}
const T& peek() {
T a = box[front];
front = next(front);
return a;
}
void printQueue() {
cout << "Front is at : " << front << endl;
cout << "Rear is at : " << rear << endl;
for (int i = 0; i < number_Of_Elements; i++) {
cout << "box[" << i << "]" << " : " << box[i] << endl;
}
cout << "------------------------" << endl;
}
void Enqueue(const T& data);
const T& Dequeue();
~Queue() {
delete[] box;
}
// error is exactly here -> };
};
Your problem is with size. You haven't declared it.
I think the compiler tries to use some global function called size instead but it fails.
After declaring the capacity member var, add
size_t size;
Demo
The answer is, there were issues, like some of the variables were not even initialized but they were being used, and the memory calculation errors were there. Like a pointer pointing somewhere in memory that actually does not exist.
I am working on a problem that requires the implementation of two ADT's. After Implementing, I need to test my bag implementations with the following template combinations:
<int, string>-- all functions
<string, int> -- insert and find functions only
My testing so far has been entering integers to test the different functions. I do not understand what it means to test the implementations with the templates.
Here is my bagADT implementation:
#include <stdlib.h>
#include "bagADT.h"
template <typename E>
class ABag : public Bag<E> {
private:
int maxSize;
int listSize;
E* listArray;
public:
ABag(int size = defaultSize) { // Constructor
maxSize = size;
listSize = 0;
listArray = new E[maxSize];
}
~ABag() { delete[] listArray; } // Destructor
bool addItem(const E& item) {
if (listSize >= maxSize) {
return false;
}
listArray[listSize] = item;
std::cout << "Add Item: Added " << item << " in spot " << listSize << std::endl;
listSize++;
return true;
}
bool remove(E& item) {
for (int i = 0; i < listSize; i++) {
if (listArray[i] == item) {
std::cout << "Remove: Removed " << item << " from position ";
item = i;
std::cout<< item << " and adjusted the location of all other elements." << std::endl;
for (i= item; i < listSize; i++) {
listArray[i] = listArray[i + 1];
}
listSize--;
return true;
}
}
return false;
}
bool removeTop(E& returnValue) {
if (listSize == 0) {
return false;
}
else {
returnValue = listArray[listSize - 1];
std::cout << "Remove Top: Removed " << returnValue << " from the top of the stack." << std::endl;
for (int i = listSize; i < maxSize; i++) {
listArray[i] = listArray[i + 1];
}
listSize--;
return true;
}
}
bool find(E& returnValue) const {
for (int i = 0; i < (listSize - 1); i++) {
if (listArray[i] == returnValue) {
returnValue = i;
return true;
}
}
return false;
}
bool inspectTop(E& item) const {
if (listSize == 0) {
return false;
}
else {
item = listArray[listSize - 1];
std::cout << "Inspect Top: The value on top is currently " << item << "." << std::endl;
return true;
}
}
void emptyBag() {
delete[] listArray;
listSize = 0;
listArray = new E[maxSize];
std::cout << "Empty Bag: Emptied the bag." << std::endl;
}
bool operator+=(const E& addend) {
if (listSize < maxSize) {
return true;
}
return false;
}
int size() const {
std::cout << "Size: Number of elements in listArray: " << listSize << std::endl;
return (listSize - 1);
}
int bagCapacity() const {
std::cout << "Bag Capacity: The capacity of this bag is " << maxSize << std::endl;
return maxSize;
}
};
Here is another file provided by my professor called kvpairs:
#ifndef KVPAIR_H
#define KVPAIR_H
// Container for a key-value pair
// Key object must be an object for which the == operator is defined.
// For example, int and string will work since they both have == defined,
// but Int will not work since it does not have == defined.
template <typename Key, typename E>
class KVpair {
private:
Key k;
E e;
public:
// Constructors
KVpair() {}
KVpair(Key kval, E eval)
{
k = kval; e = eval;
}
KVpair(const KVpair& o) // Copy constructor
{
k = o.k; e = o.e;
}
void operator =(const KVpair& o) // Assignment operator
{
k = o.k; e = o.e;
}
bool operator==(const KVpair& o) const {
if (o.k == k) {
return true;
}
return false;
}
//The following overload is provided by Adam Morrone, Spring 2016 class.
//Thanks Adam :)
friend ostream& operator<<(ostream& os, const KVpair& o) // output print operator
{
os << "Key: " << o.k << " Value: " << o.e;
return os;
}
// Data member access functions
Key key() { return k; }
void setKey(Key ink) { k = ink; }
E value() { return e; }
};
#endif
I am expected to show the test outputs using the above templates, but I have no idea how to do this. Also, ignore the += overload. It is incorrect and I know. I am supposed to overload it to directly add a new int to the array.
I think I understand now. I could be wrong, but this is my guess.
Your bag is singly templated, but it will be holding KVpair. They said they will use KVpair with <int, string> and <string, int>.
When they talk about testing it, that means they will be instantiating it as follows:
int main() {
ABag<KVPair<int, string>> bag;
bag.addItem(KVpair(1, "hi"));
//...
}
This is what I am pretty sure they mean by "testing it with templates".
As a minor edit, I don't know what C++ version you are using but if it's very archaic, you might need to write template instantiation like ABag<KVPair<int, string> > instead of putting them together. I remember vaguely this being an issue a long time ago.
I'm just a humble student looking to further my knowledge about the C++ language. My professor isn't helping! I think the title along with comments in-code explain my issues clearly.
#ifndef H_Htable
#define H_Htable
//****************************************************************
// Author: D.S. Malik
//
// This class specifies the members to implement a hash table as
// an ADT. It uses quadratic probing to resolve collisions.
//****************************************************************
#include <iostream>
#include <cassert>
using namespace std;
template <class elemType>
class hashT
{
public:
void insert(int hashIndex, const elemType& rec);
//Function to insert an item in the hash table. The first
//parameter specifies the initial hash index of the item to
//be inserted. The item to be inserted is specified by the
//parameter rec.
//Postcondition: If an empty position is found in the hash
// table, rec is inserted and the length is incremented by
// one; otherwise, an appropriate error message is
// displayed.
//sequential search
bool search(int& hashIndex, const elemType& rec, bool found = false) const;
//Function to determine whether the item specified by the
//parameter rec is in the hash table. The parameter hashIndex
//specifies the initial hash index of rec.
//Postcondition: If rec is found, found is set to true and
// hashIndex specifies the position where rec is found;
// otherwise, found is set to false.
bool isItemAtEqual(int hashIndex, const elemType& rec) const;
//Function to determine whether the item specified by the
//parameter rec is the same as the item in the hash table
//at position hashIndex.
//Postcondition: Returns true if HTable[hashIndex] == rec;
// otherwise, returns false.
void retrieve(int hashIndex, elemType& rec) const;
//Function to retrieve the item at position hashIndex.
//Postcondition: If the table has an item at position
// hashIndex, it is copied into rec.
void remove(int hashIndex, const elemType& rec);
//Function to remove an item from the hash table.
//Postcondition: Given the initial hashIndex, if rec is found
// in the table it is removed; otherwise, an appropriate
// error message is displayed.
void print() const;
//Function to output the data.
//provide for both int and string data types in the hash table
hashT(int size = 101, bool isIntTable = true);
//constructor
//Postcondition: Create the arrays HTTable and indexStatusList;
// initialize the array indexStatusList to 0; length = 0;
// HTSize = size; and the default array size is 101.
~hashT();
//destructor
//Postcondition: Array HTable and indexStatusList are deleted.
private:
elemType *HTable; //pointer to the hash table
int *indexStatusList; //pointer to the array indicating the
//status of a position in the hash table
int length; //number of items in the hash table
int HTSize; //maximum size of the hash table
};
template <class elemType>
void hashT<elemType>::insert(int hashIndex, const elemType& rec)
{
int pCount;
int inc;
pCount = 0;
inc = 1;
while (indexStatusList[hashIndex] == 1
&& HTable[hashIndex] != rec
&& pCount < HTSize / 2)
{
pCount++;
hashIndex = (hashIndex + inc) % HTSize;
inc = inc + 2;
}
if (indexStatusList[hashIndex] != 1)
{
HTable[hashIndex] = rec;
indexStatusList[hashIndex] = 1;
length++;
}
else
if (HTable[hashIndex] == rec)
cerr << "Error: No duplicates are allowed." << endl;
else
cerr << "Error: The table is full. "
<< "Unable to resolve the collision." << endl;
}
//sequential search
template <class elemType>
bool hashT<elemType>::search(int& hashIndex, const elemType& rec, bool found) const
{
for (int i = 0; i < HTSize; i++) {
if (HTable[i] == rec) { //assuming no repeat data
found = true;
hashIndex = i;
break;
}
}
return found;
}
template <class elemType>
bool hashT<elemType>::isItemAtEqual(int hashIndex, const elemType& rec) const
{
//first make sure the item has not been removed
if (indexStatusList[hashIndex] != -1) {
//make equality comparison
if (HTable[hashIndex] == rec)
return true;
else
return false; //comparison fails
}
else
{
std::cerr << "isItemEqual(): Item has been removed" << endl;
return false;
}
}
template <class elemType>
void hashT<elemType>::retrieve(int hashIndex, elemType& rec) const
{
if (indexStatusList[hashIndex] != -1)
rec = HTable[hashIndex];
else
std::cerr << "retrieve(): item has been removed" << endl;
}
template <class elemType>
void hashT<elemType>::remove(int hashIndex, const elemType& rec)
{
//make sure the item hasn't already been removed
if (indexStatusList[hashIndex] != -1) {
bool isInList = hashT<elemType>::search(hashIndex, rec);
//update the status
if (isInList)
{
indexStatusList[hashIndex] = -1;
length--; //decrement length
}
else
std::cerr << "hasT::remove() could not remove the specified item" << endl;
}
else
{
std::cerr << "remove(): Item has already been removed from the table" << endl;
}
}
template <class elemType>
void hashT<elemType>::print() const
{
std::cout << "Hash Table Data: " << endl;
for (int i = 0; i < (length - 5); i++) {
elemType item = HTable[i];
//std::cout << item << " ";
}
}
template <class elemType>
hashT<elemType>::hashT(int size, bool isIntTable)
{
HTable = new elemType[]; //is this right? HTable is an array just like indexStatusList
HTSize = size;
length = 0;
indexStatusList = new int[0]; //I think this one works?
}
template <class elemType>
hashT<elemType>::~hashT() //deleting always causes heap errors!!!
//says writing to unallocated memory -- debugging shows otherwise
{
//delete[] HTable;
//delete[] indexStatusList; //still causing errors -- error now not associated with any particular line (of my code)
}
#endif
I've kept increasing my bounds checking security when instantiating hashT in main. I'm convinced it is because my data members are being initialized incorrectly. This is one error message I get after trying a few things: "Unhandled exception at 0x773F627C (ntdll.dll) in exercise7Chap9.exe: 0xC0000374: A heap has been corrupted (parameters: 0x77426480)."
finally, here's main just in case:
#include <iostream>
#include "hashT.h"
int main() {
//add one item and test for equality
//hashT<int> ht = hashT<int>(20);
//ht.insert(0, 1);
//bool itemInsertSuccess = ht.isItemAtEqual(0, 1);
//if (itemInsertSuccess)
// std::cout << "first test has succeeded" << endl;
//else
// std::cout << "first test has failed" << endl;
////remove item and make sure isItemEqual returns false
//ht.remove(0, 1);
//bool itemRemoved = ht.isItemAtEqual(0, 1);
//if (!itemRemoved)
// std::cout << "second test passed" << endl;
//else
// std::cout << "second test failed" << endl;
//add many items then make sure search() works
hashT<int> ht1 = hashT<int>(51);
for (int i = 0; i < 10; i++)
ht1.insert(i, i);
int indx = -1;
ht1.search(indx, 0);
if (indx == 25)
std::cout << "Test 3 has passed" << endl;
else
std::cout << "Test 3 has failed" << endl;
//print data then test retrieve() and print a single item
/*ht1.print();
int item = -1;
ht1.retrieve(10, item);
if (item != -1) {
std::cout << item << endl;
std::cout << "test 4 has passed" << endl;
}
else
std::cout << "test 4 has failed" << endl;
hashT<int> HtRetrieve = hashT<int>(10);
HtRetrieve.insert(0, 0);
int it = -1;
HtRetrieve.retrieve(0, it);
std::cout << it << endl;*/
char stop;
std::cin >> stop;
//return 0;
}
In your case here, scrap the variable isIntTable. Templates are a compile-time construct and run-time values won't influence how the template is compiled into a class in any way.
Then, in your constructor, just use the template type as the one you are allocating.
template <class elemType>
hashT<elemType>::hashT(int size)
{
HTable = new elemType[size];
length = 0;
indexStatusList = new int[0];
}
However, this could be much better. Consider using initialisation instead of assignation:
hashT<elemType>::hashT(int size) :
HTable{new elemType[size]},
length{size},
indexStatusList{int[size]} { /* empty constructor */ }
And it can be even better. Consider using smart pointer instead of raw owning pointers and vectors instead of dynamic allocated array:
template<typename T>
struct hashT {
// using the right type for size
hashT(std::size_t size) : pointerToOneT{std::make_unique<T>()}, HTable(size) {}
// make_unique is the `new` for unique pointers
// no need for destructors, the vector and unique_ptr are freeing themselves
private:
std::unique_ptr<T> pointerToOneT;
std::vector<T> HTable;
std::vector<int> indexStatusList;
};
If you don't want to use std::vector, you can always use std::unique_ptr<T[]>, which is a dynamically allocated array that free itself.
template<typename T>
struct hashT {
// using the right type for size
hashT(std::size_t size) :
HTable{std::make_unique<T[]>(size)},
indexStatusList(std::make_unique<int[]>(size)) {}
private:
std::unique_ptr<T[]> HTable;
std::unique_ptr<int[]> indexStatusList;
};
EDIT
In your actual destructor, the problem is that you initialized the int* with the new[] but you are using delete. To delete an array, you must use delete[]
template <class elemType>
hashT<elemType>::~hashT()
{
delete HTable;
delete[] indexStatusList;
}
Turns out this heap corruption was caused by my lack of understanding dynamic arrays in C++.
My incorrect initialization of the arrays HTable and indexStatusList were: Htable = new elemType();, HTable = new elemType[]; and indexStatusList = new int[0];
I simply needed to add the size as an argument (never seen a size argument passed in brackets before!)
Here is the working constructor:
//constructor
template <class elemType>
hashT<elemType>::hashT(int size)
{
HTable = new elemType[size]; // pass size so the compiler knows what to allocate and deallocate
HTSize = size;
length = 0;
indexStatusList = new int[size];
}
working destructor:
template <class elemType>
hashT<elemType>::~hashT()
{
delete[] HTable;
delete[] indexStatusList;
}
I'm trying to delete "GoodBye" from the Remove function and then print a list with it missing.
I'm getting an error saying:
Error 1 error C2440: 'delete' : cannot convert from 'std::string' to 'void*
#include <iostream>
#include <string>
using namespace std;
const int SIZE = 5;
template <class New_Type>
class Array_Class
{
public:
Array_Class();
~Array_Class();
void Add(New_Type item);
int Search(New_Type item);
void Remove(New_Type item);
void Print();
private:
New_Type *A;
New_Type word;
int count;
};
template <class New_Type>
Array_Class<New_Type>::Array_Class()
{
cout << "You are inside the default constructor.\n";
cout << "New_Type has a size of " << sizeof(New_Type) << " bytes\n\n";
count = 0;
A = new New_Type[SIZE];
}
template <class New_Type>
Array_Class<New_Type>::~Array_Class()
{
cout << "The Destructor has been called.\n\n";
delete[] A;
count = 0;
A = 0;
}
template <class New_Type>
void Array_Class<New_Type>::Add(New_Type item)
{
if (count<SIZE)
{
A[count++] = item;
}
else
{
cout << "The array is full.\n";
}
}
template <class New_Type>
int Array_Class<New_Type>::Search(New_Type item)
{
int i;
for (i = 0; i<count; i++)
{
if (item == A[i])
{
return i;
}
}
return -1;
}
item is Goodbye. word will save the copy that gets deleted.
template <class New_Type>
void Array_Class<New_Type>::Remove(New_Type item)
{
int i;
word = item;
for (i = 0; i < count; i++)
{
if (item == A[i])
{
delete A[i];
}
}
}
template <class New_Type>
void Array_Class<New_Type>::Print()
{
int i;
for (i = 0; i<count; i++)
{
cout << "A[" << i << "] = " << A[i] << endl;
}
}
The main function which will add "GoodBye" and other words to my_String.
int main()
{
Array_Class<string> my_String;
Array_Class<int> my_Ints;
Array_Class<char> my_Chars;
my_String.Add("Hello");
my_String.Add("GoodBye");
my_String.Add("ComeHere");
my_String.Add("SayNo");
my_Chars.Add('a');
my_Chars.Add('b');
my_Chars.Add('c');
my_Chars.Add('d');
my_Chars.Add('e');
my_Chars.Add('f');
my_Chars.Add('g');
my_String.Print();
my_Ints.Print();
my_Chars.Print();
cout << endl;
my_String.Search("Hello");
my_String.Search("SayNo");
my_String.Remove will remove GoodBye from my_String:
my_String.Remove("GoodBye");
my_String.Print();
return 0;
}
The problem is that your Remove function should not be issuing any calls to delete. What it should be doing is shifting the elements "up" by one and decreasing the count member variable. This in effect "removes" the item from the Array.
To shift the elements up, you write a loop where you replace element i with element i+1, where you start the loop at the item you want to remove.
However your array is dynamically allocated, you can't just call delete on particular elements of it. This is a contiguous block of memory. You can do what #PaulMcKenzie said - To find element that matches element passed as an argument to Remove function and then shift to the left remaining array elements, then decrease count member variable. I solved it, but since this is homework posting it wouldn't be wise. Here's a very weird pseudo-code of mine. I hope you understand that concept.
//array elements : Hello, GoodBye, ComeHere, SayNo
my_String.Remove("GoodBye");
// found index of element to remove = 1;
// decrement count
// loop from saved index through count-1:
// A[i] = A[i+1];
// There will be two iterations of this loop. here's how array would look like:
// 1st: array elements : Hello, ComeHere, ComeHere, SayNo
// 2nd: array elements : Hello, ComeHere, SayNo, SayNo
Then, because of decrementing count, last element won't be printed.
And in c++, for dynamic arrays std::vector is way to go.
Basically a dynamic array, which has circular rotation when is full. You have access to every element and you can change it's value, however you can insert and remove only from both ends.(constant time). Most of the methods seem to be working fine, however at certain "push" numbers I get wrong output.
For example first input is 1,2,3 then I insert 4 at the end. Next output is: 2,3,4 However after I insert 5 at the end the output is 2, 3, 5
I have no idea what is causing this. I am posting the entire source code below (atleast the functions which have to do with the tests where the error must hide). There is some documentation in the file and an example of the error in case I haven't explained things clearly.
#include <iostream>
using namespace std;
template <typename Object>
class ArrayVector {
private:
int capacity; // capacity
int sz; // number of elements
Object* a;
int f; // start of the indexes
int b; // end of the indexes
public:
ArrayVector(int initCap);
~ArrayVector();
int size() const { return sz; }
bool isEmpty() const { return size() == 0; }
Object elemAtRank(int r);
void pushBack( const Object& e);
void pushFront(const Object& e);
void popBack();
void popFront();
};
template <typename Object> // constructor
ArrayVector<Object>::
ArrayVector(int initCap) {
capacity = initCap;
sz = 0;
a = new Object[capacity];
f = 0;
b = 0;
}
template <typename Object> // gets the element at a certain rank
Object ArrayVector<Object>:: elemAtRank(int r)
{
return a[(f + r) % sz]; // starting position in real array + r % number of elements
}
template <typename Object>
void ArrayVector<Object>:: pushBack( const Object& e)
{
if(sz == capacity && sz > 0) // if the array is full time to spin it
{
if(f == capacity){ // Handles the front.
f = 0; // if the front is equal to the capacity
// set it to zero, else increment
}else{
f++;
}
if(b == capacity){ //Handles the back
b = 0; //if the back is equal to the capacity
// cout<< "SC insert "<< e << " at "<< b <<endl;
a[b] = e;
}else{ // set it to zero, else increment
a[b] = e;
// cout<< "SC insert "<< e << " at "<< b <<endl;
b++;
}
}else{
a[b] = e;
// cout<< "insert "<< e << " at "<< b <<endl;
b++;
sz++;
}
}
template <typename Object>
void ArrayVector<Object>:: pushFront( const Object& e)
{
if(f == 0){
f = capacity-1;
}else{
f--;
}
a[f] = e;
if(sz< capacity)
sz++;
}
int main()
{
// Fill array and print it
cout << "Fill with numbers" << endl;
ArrayVector<int> asd(3);
asd.pushBack(1);
asd.pushBack(2);
asd.pushBack(3);
for(int i =0; i < asd.size(); i++)
cout << asd.elemAtRank(i) << endl;
//Test if it spins
cout << "BEGIN Spin TEST " << endl;
asd.pushBack(4);
cout << "First test is ok" << endl;
for(int i =0; i < asd.size(); i++)
cout << asd.elemAtRank(i) << endl;
// here the error comes
asd.pushBack(5);
cout << "On the second iteration things crash and burn" << endl;
for(int i =0; i < asd.size(); i++)
cout << asd.elemAtRank(i) << endl;
return 0;
}
In addition to your insertion times not matching your desired requirements, your issue is here:
template <typename Object>
void ArrayVector<Object>:: pushFront( const Object& e)
{
if(f == 0)
{
f = capacity-1;
}
else
{
f--;
}
a[f] = e; // problem lies here!
if(sz < capacity)
sz++;
}
You are figuring out where to do the insert, but you are not pushing the other elements around the vector; that is, you are just overwriting the element at the insertion point. If you wanted to push it onto the front, you would need to copy the other elements over 1 position each and then do your insert. A better solution (which would match your constant insertion time requirement) would be to implement it as a double-linked list. Pushing onto the ends would simply require the following pseudo-code:
void push_front(const Object& o)
{
if (size == capacity)
l.pop_back();
l.push_front(o);
}
If you really must use a contiguous memory block, you will not get constant-time insertion, but it would look like this:
// Assumptions: 0 is always the front, capacity-1 is always the maximum back
template <typename Object>
void ArrayVector<Object>:: pushFront( const Object& e)
{
// assume capacity > 0, move all the elements to the right one slot
for (int i = capacity - 1; i > 0; --i)
{
a[i] = a[i - 1];
}
a[0] = e;
if(sz < capacity)
sz++;
}