//====================================================================== // File: vector.h // Author: Timothy A. Budd // Description: This file contains the interface and implementation // of the vector template classes. // // Copyright (c) 1992 by Timothy A. Budd. All Rights Reserved. // may be reproduced for any non-commercial purpose //====================================================================== #ifndef VECTOR_H #define VECTOR_H #include #include #include "iterator.h" //---------------------------------------------------------------------- // class vector // type safe and access safe vector data type // permits dynamic modification of vector length //---------------------------------------------------------------------- template class vector { public: // constructors and destructor vector(): data(0), size(0) {}; vector(unsigned int numberElements); vector(unsigned int numberElements, T initialValue); vector(const vector & source); virtual ~vector(); // access to elements via subscript // declared here to be inline T & operator [] (unsigned int index) const { // subscript a vector value // check that index is valid assert(index < size); // return requested element return data[index]; }; // assignment vector & operator = (const vector &); // other operations void fill (const T value); // length of vector unsigned int length() const { return size; }; // dynamically change size unsigned int setSize(unsigned intnumberOfElements); unsigned int setSize(unsigned intnumberOfElements, T initialValue); ostream & print(ostream & str); protected: // data areas T * data; unsigned int size; }; //---------------------------------------------------------------------- // class boundedVector // vectors with explicit upper and lower bounds //---------------------------------------------------------------------- template class boundedVector : public vector { public: // constructors boundedVector(int lowIndex, int highIndex); boundedVector(int lowIndex, int highIndex, T & initialValue); boundedVector(const boundedVector & source); // element access. T & operator [] (int index) const; // structural information int lowerBound() const; int upperBound() const; protected: int lowbound; }; //---------------------------------------------------------------------- // class vectorIterator // iterator protocol used to loop over vector elements //---------------------------------------------------------------------- template class vectorIterator : public iterator { public: // constructor vectorIterator(vector &); vectorIterator(const vectorIterator &); // iterator protocol virtual int init(); virtual T & operator ()(); virtual int operator !(); virtual int operator ++(); virtual void operator =(T newValue); // new methods specific to vector iterators int operator --(); int key(); protected: // data fields unsigned int currentKey; vector & data; }; // // class orderedVector // vector maintained in sorted order // template class orderedVectorIterator; template class orderedVector { public: // constructors orderedVector(); orderedVector(const orderedVector & v); // subscript operation T & operator [ ] (unsigned int index) const; // protocol for searching void add (T value); void deleteAllValues (); int includes (T value) const; int isEmpty () const; void remove (T value); private: // data area is vector for values vector data; friend class orderedVectorIterator; }; template class orderedVectorIterator : public vectorIterator { public: orderedVectorIterator(orderedVector &); }; template inline orderedVectorIterator::orderedVectorIterator(orderedVector & x) : vectorIterator(x.data) { // no further initialization } // // class matrix // two dimensional arrays // template class matrix { public: matrix(unsigned int numberOfRows, unsigned int numberOfColumns); matrix(unsigned int numberOfRows, unsigned int numberOfColumns, T initialValue); ~matrix(); vector & operator [ ] (unsigned int index) const; int numberRows() const; int numberColumns() const; private: vector *> rows; }; // // class enumVector // vector abstraction index by // elements of an enumerated type // template class enumVector : public vector { public: // constructors enumVector(E max); enumVector(const enumVector & v); // operations T & operator [ ] (E index); }; //---------------------------------------------------------------------- // class vector implementation //---------------------------------------------------------------------- template vector::vector(unsigned int numberElements) : size(numberElements) { // create and initialize a new vector // allocate the space for the elements data = new T[size]; // check that allocation was successful assert(data != 0); } template vector::vector(unsigned int numberElements, T initialValue) : size(numberElements) { // create and initialize a new vector // allocate the space for the elements data = new T[size]; assert(data != 0); // set each element to the initial value for (int i = 0; i < size; i++) data[i] = initialValue; } template vector::vector(const vector & source) : size(source.size) { // create and initialize a new vector // allocate the space for the elements data = new T[size]; assert(data != 0); // copy values from old vector for (int i = 0; i < size; i++) data[i] = source.data[i]; } template vector::~vector() { // free teh dynamic memory buffer delete [] data; data = 0; } template vector & vector::operator = (const vector & right) { // match sizes if (size != right.size) setSize(right.size); // copy the elements for (int i = 0; i < right.size; i++) data[i] = right.data[i]; // return current value return *this; } // fill the vector with a constant template void vector::fill(const T value) { for (int i = 0; i < size; i++) { data[i] = value; } } template unsigned int vector::setSize (unsigned int numberOfElements) { // dynamically alter the size of the vector // first create the new data area T * newData = new T[numberOfElements]; assert(newData != 0); if (data) { if (numberOfElements <= size) { // data area is shrinking - copy as many elements as possible for (int i = 0; i < numberOfElements; i++) newData[i] = data[i]; } else { // data area is growing - first copy old values for (int i = 0; i < size; i++) newData[i] = data[i]; } // delete the old data buffer delete [] data; } // update the data member fields size = numberOfElements; data = newData; // return new size return size; } template unsigned int vector::setSize (unsigned int numberOfElements, T initialValue) { // the following are for a g++ compiler bug int i; T * newData; // dynamically alter the size of the vector // first create the new data area newData = new T[numberOfElements]; assert(newData != 0); if (numberOfElements <= size) { // data area is shrinking - copy as many elements as possible for (i = 0; i < numberOfElements; i++) { newData[i] = data[i]; } } else { // data area is growing - first copy old values for (i = 0; i < size; i++) { newData[i] = data[i]; } // then initialize new values for (i = size; i < numberOfElements; i++) newData[i] = initialValue; } // delete the old data buffer delete [] data; // update the data member fields size = numberOfElements; data = newData; // return new size return size; } // dot product template T dot (const vector & left, const vector & right) { assert(left.length() == right.length()); T answer = 0; for (int i = 0; i boundedVector::boundedVector (int lowIndex, int highIndex) : lowbound(lowIndex), vector(1 + highIndex - lowIndex) { // create and initialize a new bounded vector assert(lowIndex <= highIndex); } template boundedVector::boundedVector (int lowIndex, int highIndex, T & initialValue) : lowbound(lowIndex), vector(1 + highIndex - lowIndex, initialValue) { // create and initialize a new bounded vector assert(lowIndex <= highIndex); } template boundedVector::boundedVector (const boundedVector & source) : lowbound(source.lowbound), vector(source) { // no further initialization necessary } template T & boundedVector::operator [](int index) const { // subscript operator for bounded vectors // subtract off lower bound // yielding value between 0 and size of vector // then use subscript from parent class return vector::operator [](index - lowbound); } template int boundedVector::lowerBound() const { // return smallest legal index for bounded vector return lowbound; } template int boundedVector::upperBound() const { // return largest legal index for bounded vector return lowerBound() + length() - 1; } //---------------------------------------------------------------------- // class vectorIterator implementation //---------------------------------------------------------------------- template vectorIterator::vectorIterator(vector & v) : data(v) { // create and initialize a vector iterator init(); } template vectorIterator:: vectorIterator(const vectorIterator & x) : data(x.data), currentKey(x.currentKey) { // no further initialization } template int vectorIterator::init() { // set current key to firstelement currentKey = 0; return operator !(); } template T & vectorIterator::operator ()() { // return current value return data[currentKey]; } template int vectorIterator::operator !() { // return true if there is a current element return currentKey < data.length(); } template int vectorIterator::operator ++() { // advance to the next element currentKey++; return operator !(); } template void vectorIterator::operator = (T newValue) { // change the current index value data[currentKey] = newValue; } template int vectorIterator::operator --() { // move current key back one element if (currentKey > 0) currentKey--; return operator !(); } template int vectorIterator::key() { // return index of current value return currentKey; } //---------------------------------------------------------------------- // class matrix implementation //---------------------------------------------------------------------- template matrix::matrix(unsigned int numberOfRows, unsigned int numberOfColumns) : rows(numberOfRows) { // create and initialize a new matrix value // now allocate each row of data for (unsigned int i = 0; i < numberOfRows; i++) { rows[i] = new vector(numberOfColumns); // check that allocation was successful assert(rows[i] != 0); } } template matrix::matrix(unsigned int numberOfRows, unsigned int numberOfColumns, T initialValue) : rows(numberOfRows) { // create and initialize a new matrix value // now allocate each row of data for (unsigned int i = 0; i < numberOfRows; i++) { rows[i] = new vector(numberOfColumns, initialValue); // check that allocation was successful assert(rows[i] != 0); } } template matrix::~matrix() { // free up dynamic storage allocated by matrix object unsigned int max = rows.length(); for (unsigned int i = 0; i < max; i++) { // some compilers do not allow // subscripted variables in delete //vector * p = rows[i]; //delete p; rows[i] = 0; } } template vector & matrix::operator [ ] (unsigned int index) const { // return elemement (vector) index by value // check that reference is valid assert(rows[index] != 0 ); // return vector value return * rows[index]; } template int matrix::numberRows() const { // return number of rows in vector return rows.length(); } template int matrix::numberColumns() const { // return number of columns in vector return rows[0]->length(); } //---------------------------------------------------------------------- // class enumVector implementation //---------------------------------------------------------------------- template enumVector::enumVector(E max) : vector(1 + int(max)) { // create and initialize an instance of enumerated vector } template enumVector::enumVector(const enumVector & source) : vector(source) { // create and initialize an instance of enumerated vector } template T & enumVector::operator [ ] (E index) { // subscript an enumerated vector // simply convert enumerated index value into integer return vector::operator [ ] (int(index)); } // ******************************************************* // template functions // Cfront demands these are in a different file, // g++ and borland want them in this file. // ******************************************************* # ifdef __GNUG__ # include "vector.C" # endif # ifndef __GNUG__ template int binarySearch(VecType data, EleType ele, unsigned int max); template void swap( vector & data, int i, int j); template void bubbleSort(vector & data); template void selectionSort(vector & data); template void insertionSort(vector & data); template int partition(vector & v, int low, int high, int pivotIndex); template T findElement(vector & v, int N, int low, int high); template void quackSort(vector & v, int low, int high); template void quackSort(vector & v); # endif // // implementation of ordered vectors // template orderedVector::orderedVector() : data(0) { // no further initialization required } template T & orderedVector::operator [ ] (unsigned int index) const { return data[index]; } template orderedVector::orderedVector(const orderedVector & v) : data(v.data) { // no further initialization required } template void orderedVector::deleteAllValues() { // set the size of the vector to zero // thereby deleting all values data.setSize(0); } template int orderedVector::isEmpty() const { // collection is empty if vector is length zero return data.length() == 0; } template void orderedVector::add(T value) { // get the current length of the vector unsigned int max = data.length(); // perform binary search to find proper location for element unsigned int index = binarySearch(data, value, max); // grow vector to new size data.setSize(max + 1); // move everything up to make space for (unsigned int i = max; i > index; i--) data[i] = data[i-1]; // place element in location data[index] = value; } template int orderedVector::includes(T value) const { // see if vector includes given element unsigned int max = data.length(); unsigned int index = binarySearch(data, value, max); // if value is the right element, return 1 if (index < max) if (value == data[index]) return 1; // not found return 0; } template void orderedVector::remove(T value) { // remove a value from collection, if present unsigned int max = data.length(); unsigned int index = binarySearch(data, value, max); // if value is the right element, return 1 if (index < max) if (value == data[index]) { // found element, remove it max = max - 1; for (unsigned int i = index; i < max; i++) data[i] = data[i+1]; // then change the size of the vector data.setSize(max); } } template ostream & vector::print (ostream & str) { str << "["; for (int i = 0; i < size; i++) { str << data[i]; if (i + 1 < size) str << " "; } return str << "]"; } template ostream & operator << (ostream & str, vector & v) { return v.print(str); } template istream & operator >> (istream & istr, vector & target) { // read in a vector of objects surrounded by square brackets // grow the target as needed unsigned int size = target.length(); unsigned int nread = 0; char delim; istr >> delim; if (delim != '[') { cerr << "Found `" << delim << "' where `[' was expected." << endl; } assert(delim == '['); do { istr >> delim; if (delim == ']') break; istr.putback(delim); T val; istr >> val; if (nread >= size) { size = target.setSize(2 * nread + 1); } target[nread] = val; nread++; } while (istr); // now set the size to the exact size required. target.setSize(nread); return istr; } #endif