This file is used by the above test programs ...
UPDATE: Now with forward and reverse iterators
// Vector2.h // // this version 2013-06-15 //
// with merge sort and insertion sort ... and added ...
// resize, pack ... and ...
// size constructor,
// copy constuctor, array constructor and overloaded operator=
#ifndef dwVECTOR_H
#define dwVECTOR_H
#include <iostream>
/* can re-set this to minimize copying and getting new memory using push_back */
#ifndef VEC_CHUNK_SIZE
#define VEC_CHUNK_SIZE 8
#endif
template < typename T >
class Vector
{
public:
Vector();
Vector( int n );
Vector( const Vector< T >& ); // copy constructor ...
Vector( const T*, const T* ); // array constructor ...
Vector<T>& operator= ( const Vector< T >& v ); // overloaded operator=
~Vector() { clear(); }
void push_back( const T& );
void reserve( int );
void resize( int );
void shrink( int );
void pack();
void clear();
T& operator [] (int i) { return ary[i]; }
const T& operator [] (int i) const { return ary[i]; }
class iterator
{
public:
iterator( T* p = 0 ) : ptr(p) {}
iterator& operator ++ () { ++ptr; return *this; }
iterator& operator ++ ( int ) { ++ptr; return *this; }
iterator& operator -- () { --ptr; return *this; }
iterator& operator -- ( int ) { --ptr; return *this; }
bool operator != (const iterator & it2) const { return ptr != it2.ptr; }
bool operator == (const iterator & it2) const { return ptr == it2.ptr; }
const T& operator * () const { return *ptr; }
T& operator * () { return *ptr; }
private:
T* ptr; // cur
} ;
iterator begin() { iterator it( ary ); return it; }
iterator end() { iterator it( ary + len ); return it; }
class reverse_iterator
{
public:
reverse_iterator( T* p = 0 ) : ptr(p) {}
reverse_iterator& operator ++ () { --ptr; return *this; }
reverse_iterator& operator ++ ( int ) { --ptr; return *this; }
reverse_iterator& operator -- () { ++ptr; return *this; }
reverse_iterator& operator -- ( int ) { ++ptr; return *this; }
bool operator != (const reverse_iterator & it2) const { return ptr != it2.ptr; }
bool operator == (const reverse_iterator & it2) const { return ptr == it2.ptr; }
const T& operator * () const { return *ptr; }
T& operator * () { return *ptr; }
private:
T* ptr; // cur
} ;
reverse_iterator rbegin() { reverse_iterator it( ary + len-1 ); return it; }
reverse_iterator rend() { reverse_iterator it( ary-1 ); return it; }
int size() const { return len; }
int capacity() const { return cap; }
bool get_isSorted() const { return isSorted; }
void set_isSorted() { isSorted = true; }
bool isSortedUp() const;
int find( T ) const; // returns index if T value present ... else -1
void erase( int ); // if int index valid, erases element there
void erase( int, int ); // if int index valid, erases n elements there
void insert( int, int, const T& );
void msort();
void isort();
void unique();
bool isUnique() const ;
private:
int cap; // capacity
int len;
bool isSorted;
T* ary;
void enlarge(); // used by push_back
void merge( int, int, int, Vector< T >& ); // used by msort ...
void my_msort( int, int, Vector< T >& );
};
// definitions ...
template < typename T >
Vector< T >::Vector() : cap(0), len(0), isSorted(true), ary(0) {}
template < typename T >
Vector< T >::Vector( int n ) : cap(0), len(0), isSorted(true), ary(0)
{
if( n > 0 )
{
cap = len = n;
if( len > 1 ) isSorted = false;
ary = new T[size];
for( int i = 0; i < len; ++i ) ary[i] = T(0);
}
}
template < typename T >
Vector< T >::Vector( const Vector< T > & v ) // copy constructor ...
{
cap = v.cap;
len = v.len;
isSorted = v.isSorted;
ary = new T[cap];
for( int i = 0; i < len; ++i ) ary[i] = v.ary[i];
}
template < typename T >
Vector< T >::Vector( const T* a, const T* b ) // array constructor ... NOTE! b is one past last element
{
len = cap = b-a;
isSorted = false;
ary = new T[cap];
for( int i = 0; i < len; ++i ) ary[i] = a[i];
}
template < typename T >
Vector< T >& Vector< T >::operator= ( const Vector< T >& v ) // overloaded operator=
{
if( this != &v )
{
delete [] ary;
cap = v.cap;
len = v.len;
isSorted = v.isSorted;
ary = new T[cap];
for( int i = 0; i < len; ++i ) ary[i] = v.ary[i];
}
return *this;
}
template < typename T >
void Vector< T >::push_back( const T& e )
{
if( len == cap ) enlarge();
/* now add in new Rec ... */
ary[len] = e;
++ len;
isSorted = false;
}
// new array to hold 2x's records ... copies old to new
template < typename T >
void Vector< T >::enlarge()
{
if( cap ) cap += cap; // double capacity ...
else cap = VEC_CHUNK_SIZE; // set initial capacity
T* tmp = new T[ cap ];
for( int i = len-1; i >= 0; --i ) tmp[i] = ary[i];
//for( int i = cap-1; i >= len; --i ) tmp[i] = 0;
delete [] ary;
ary = tmp; // update the base address of ary
}
template < typename T >
void Vector< T >::reserve( int newCap )
{
if( newCap > cap )
{
cap = newCap;
T* tmp = new T[ cap ];
for( int i = len-1; i >= 0; --i ) tmp[i] = ary[i];
delete [] ary;
ary = tmp; // update the base address of ary
}
}
template < typename T >
void Vector< T >::resize( int newSize )
{
if( newSize > len )
{
reserve( newSize );
for( int i = cap-1; i >= len; --i ) ary[i] = T(0);
len = newSize;
isSorted = false;
}
else if( newSize < len )
{
shrink( newSize );
//pack(); // ? //
}
}
template < typename T >
void Vector< T >::shrink( int newSize )
{
if( newSize < len && newSize >= 0 ) len = newSize; // leave cap unchanged
if( len < 2 ) isSorted = true;
}
template < typename T >
void Vector< T >::pack()
{
if( len < cap )
{
cap = len;
T* tmp = new T[cap];
for( int i = len-1; i >= 0; --i ) tmp[i] = ary[i];
delete [] ary;
ary = tmp; // update address ...
}
}
template < typename T >
void Vector< T >::clear()
{
if( ary != 0 )
{
delete [] ary;
cap = len = 0;
ary = 0;
isSorted = true;
}
}
template < typename T >
int Vector< T >::find( T value ) const // returns index if present ... else -1
{
for( int i = 0; i < len; ++i )
if( ary[i] == value ) return i;
// else if reach here ...
return -1;
}
template < typename T >
void Vector< T >::erase( int index ) // if index valid, erases element there
{
if( ! len )
{
std::cout << "\nERROR! Vector empty." << std::endl;
return;
}
//else ...
if( index < 0 || index >= len )
{
std::cout << "\nERROR! Index " << index
<< " out of range 0.." << len-1 << std::endl;
return;
}
// else ...
for( int i = index; i < len-1; ++i )
ary[i] = ary[i+1]; // copy each element above, down one index, so erased
// now update len for 'this' vector object ...
-- len;
}
template < typename T >
void Vector< T >::erase( int index, int num ) // if index valid, erases n elements there
{
if( ! len )
{
std::cout << "\nERROR! Vector empty." << std::endl;
return;
}
//else ...
if( index < 0 || index >= len )
{
std::cout << "\nERROR! Index " << index
<< " out of range 0.." << len-1 << std::endl;
return;
}
//else ...
if( num > len - index )
{
num = len - index;
std::cout << "\nERROR! num to erase " << num
<< " out of range 0.." << len-index << std::endl;
return;
}
// else ...
for( int i = index; i < len-num; ++i )
ary[i] = ary[i+num]; // copy nth element above, down n places, so erased
// now update len for 'this' vector object ...
len -= num;
}
// default is push_front one '0' value element
template < typename T > // assumes pos >= 0, num > 0
void Vector< T >::insert( int pos = 0, int num = 1, const T& val = T(0) )
{
if( pos < 0 || num < 1 )
{
std::cout << "\nERROR! Index must be >= 0 and num must be > 1 \n";
return;
}
if( cap < len + num ) reserve( len + num ); // updates cap
if( pos > cap-num ) pos = len; // just add in ... at end ...
else if( pos < len ) // shift last 'len-pos' elements up num places ....
{
int top = len + num - 1;
for( int i = 0; i < len-pos; ++i ) { ary[top] = ary[top-num]; --top; }
}
for( int i = 0; i < num; ++ i ) ary[pos+i] = val; // insert val's
len += num; // update len
isSorted = false;
}
template < typename T >
bool Vector< T >::isSortedUp() const
{
int sizeTmp = len;
while( --sizeTmp )
if( ary[sizeTmp] < ary[sizeTmp-1] ) return false;
return true;
}
/* * * * * * * * * * * * * * merge sort / isort * * * * * * * * * * * * * * * */
template < typename T >
void Vector< T >::merge( int bot, int mid, int top, Vector< T >& tmp )
{
int sz = top - bot + 1; // len of the range to be merged
int j = 0; // next open index in tmp
int h1 = bot; // next index to consider in the 1st half
int h2 = mid + 1; // next index to consider in the 2nd half
// while indexes h1 and h2 are not past their ends ...
while( h1 <= mid && h2 <= top )
{ // move the smaller element into the tmp vec...
if( ary[h1] < ary[h2] ) tmp[j++] = ary[h1++];
else tmp[j++] = ary[h2++];
}
// Note: only one of the two while loops below is executed ...
while( h1 <= mid ) tmp[j++] = ary[h1++]; // copy any remaining entries (1st half)
while( h2 <= top ) tmp[j++] = ary[h2++]; // copy any remaining entries (2nd half)
for( j = 0; j < sz; ++j ) ary[bot+j] = tmp[j]; // copy back sorted tmp vec...
}
template < typename T >
void Vector< T >::my_msort( int bot, int top, Vector< T >& tmp )
{
if( bot == top ) return;
else
{
int mid = ( bot + top ) / 2;
my_msort( bot, mid, tmp ); // sort the first ...
my_msort( mid + 1, top, tmp ); // and the second half ...
merge( bot, mid, top, tmp ); // now merge these 2 sorted chunks
}
}
template < typename T >
void Vector< T >::msort()
{
if( isSorted ) return;
if( len > 1 )
{
Vector< T > tmp;
tmp.reserve( len );
my_msort( 0, len-1, tmp );
isSorted = true;
}
}
template < typename T >
void Vector< T >::isort()
{
if( isSorted ) return;
// start with an array of just the first 2 elements (if exists)
for( int i = 1; i < len; ++i )
{
T cmp = ary[i]; // get copy of this new cmp element on each outer loop
int j = i-1; // get index of element just to the left of the above 'cmp'
// to start comparisons
while( j >= 0 && cmp < ary[j] )
{
ary[j+1] = ary[j]; // copy element 'up' ...
--j; // decrement j in preparation for next inner loop
}
ary[j+1] = cmp; // insert element at index j+1 (since j was decremented above)
}
isSorted = true;
}
/* * * * * * * * * * * * * * merge sort / isort * * * * * * * * * * * * * * * */
template < typename T >
void Vector< T >::unique()
{
if( !isSorted ) msort();
int i = 0;
for( int j = 1; j < len ; ++j )
{
if( ary[i] != ary[j] )
{
++i;
if( i != j ) ary[i] = ary[j];
}
}
len = ++i;
}
template < typename T >
bool Vector< T >::isUnique() const
{
if( !isSorted ) msort();
for( int i = len-1; i > 0; --i )
if( ary[i] == ary[i-1] ) return false;
// else ...
return true;
}
template < typename T >
void merge( Vector< T >& v, int bot, int mid, int top, Vector< T >& tmp, bool (*cmp) (const T& a, const T& b ) )
{
int sz = top - bot + 1; // size of the range to be merged
int j = 0; // next open index in tmp
int h1 = bot; // next index to consider in the 1st half
int h2 = mid + 1; // next index to consider in the 2nd half
// while indexes h1 and h2 are not past their ends ...
while( h1 <= mid && h2 <= top )
{ // move the 'true' element into the tmp vec...
if( cmp(v[h1], v[h2]) ) tmp[j++] = v[h1++];
else tmp[j++] = v[h2++];
}
// Note: only one of the two while loops below is executed ...
while( h1 <= mid ) tmp[j++] = v[h1++]; // copy any remaining entries (1st half)
while( h2 <= top ) tmp[j++] = v[h2++]; // copy any remaining entries (2nd half)
for( j = 0; j < sz; ++j ) v[bot+j] = tmp[j]; // copy back sorted tmp vec...
}
template < typename T >
void my_msort( Vector< T >& v, int bot, int top, Vector < T >& tmp, bool (*cmp) (const T& a, const T& b ) )
{
if( bot == top ) return;
else
{
int mid = ( bot + top ) / 2;
my_msort( v, bot, mid, tmp, cmp ); // sort the first ...
my_msort( v, mid + 1, top, tmp, cmp ); // and the second half ...
merge( v, bot, mid, top, tmp, cmp ); // now merge these 2 sorted chunks
}
}
template < typename T >
void msort( Vector< T >& v, bool (*cmp) (const T& a, const T& b ) )
{
if( v.size() > 1 )
{
Vector< T > tmp;
int size = v.size();
tmp.reserve( size );
my_msort( v, 0, size-1, tmp, cmp );
v.set_isSorted();
}
}
#endif