Vector C + + language implementation of basic data structure and algorithm

0 - General

The code is based on data structure C + + language version by Mr. Deng Junhui, with appropriate changes.
It feels like this is basically a simplified STL.
Follow the book and review the basics of C + + language.

1 - interface declaration

The vector class is implemented here. In order to distinguish it from the vector in the standard library, the beginning character is capitalized.
In consideration of reusability, the template class is adopted here, and it is assumed that the instance of the class supports comparison operations and judgment operations, or the class has overloaded the comparison operators <, > and judgment operators = =.
In addition, in order to make the idea clearer, some robustness considerations are sacrificed. For example, the legitimacy of the incoming parameter rank r is not checked, which may cause the array to cross the boundary.

#ifndef _VECTOR_H_
#define _VECTOR_H_

#define DEFAULT_CAPACITY 3

typedef int Rank;

//As a sort parameter, it is used to call different sorting algorithms
enum SortMethod {
    BUBBLE_SORT,
    INSERTION_SORT,
    SHELL_SORT,
    SELECTION_SORT,
    HEAP_SORT,
    MERGE_SORT_ITERATIVELY,
    MERGE_SORT_RECURSIVELY,
    QUICK_SORT,
    COUNTING_SORT,
    RADIX_SORT
};

//As a parameter of search, it is used to call different search algorithms
enum SearchMethod {
    BIN_SEARCH,
    FIB_SEARCH
};

template <typename T>
class Vector {
   public:
    //Default constructor: the capacity is c, the size is s, and all are initialized to v
    Vector(int c = DEFAULT_CAPACITY, int s = 0, T v = 0);
    //Use array global construction
    Vector(T const* A, Rank n);
    //Using array interval construction
    Vector(T const* A, Rank lo, Rank hi);
    //Using vector global copy construction
    Vector(Vector<T> const& V);
    //Using vector interval construction
    Vector(Vector<T> const& V, Rank lo, Rank hi);

    ~Vector();

    /****Read only access interface****/
    //Return scale
    Rank size() const;
    //Air judgment
    bool empty() const;
    //Returns the number of adjacent pairs in reverse order
    int disordered() const;
    //Global search of unordered vectors
    Rank find(T const& e) const;
    //Unordered vector interval search
    Rank find(T const& e, Rank lo, Rank hi) const;
    //Ordered vector global search
    Rank search(T const& e, SearchMethod m = BIN_SEARCH) const;
    //Ordered vector interval search
    Rank search(T const& e, Rank lo, Rank hi, SearchMethod m = BIN_SEARCH) const;

    //Overloaded subscript operator []
    T& operator[](Rank r) const;
    //Overloaded assignment operator =, which is convenient for direct copy, and returned reference is convenient for chained assignment
    Vector<T>& operator=(Vector<T> const& V);

    //Delete elements with rank r
    T remove(Rank r);
    //Delete elements with rank between [lo,hi)
    int remove(Rank lo, Rank hi);
    //Insert element
    Rank insert(Rank r, T const& e);
    //Insert as end by default
    Rank insert(T const& e);
    //Interval sorting
    void sort(Rank lo, Rank hi, SortMethod m = BUBBLE_SORT);
    //Overall sorting
    void sort(SortMethod m = BUBBLE_SORT);
    //Interval scrambling
    void unsort(Rank lo, Rank hi);
    //Overall scrambling
    void unsort();
    //Disordered vector de duplication
    int deduplicate();
    //Ordered vector de duplication
    int uniquify();

    //Traversal using function pointers
    void traverse(void (*)(T&));
    //Traversal using a functor (function object)
    template <typename VST>
    void traverse(VST&);

   protected:
    Rank _size;
    int _capacity;
    T* _elem;

    //Copy array
    void copyFrom(T const* A, Rank lo, Rank hi);
    //Capacity expansion
    void expand();
    //shrink
    void shrink();
    //Bubble sorting
    void bubbleSort(Rank lo, Rank hi);
    //Insert sort
    void insertionSort(Rank lo, Rank hi);
    //Shell Sort 
    void shellSort(Rank lo, Rank hi);
    //Pick maximum
    Rank max(Rank lo, Rank hi);
    //Select sort
    void selectionSort(Rank lo, Rank hi);
    //Heap sort
    void heapSort(Rank lo, Rank hi);
    //Merge sort iterative version
    void mergeSort_iteratively(Rank lo, Rank hi);
    //Ordered subsequence merging
    void merge(Rank lo, Rank mi, Rank hi);
    //Merge sort recursive version
    void mergeSort_recursively(Rank lo, Rank hi);
    //Pivot point structure
    Rank partition(Rank lo, Rank hi);
    //Quick sort
    void quickSort(Rank lo, Rank hi);
    //Count sort
    void countingSort(Rank lo, Rank hi);
    //Cardinality sort
    void radixSort(Rank lo, Rank hi);

};  //Vector

#endif

2 - Interface Implementation

2.1 - constructors and destructors

There are five versions of constructors and a destructor with access rights of public.

The default constructor will request #define default_ Capability is an array space of size 3 and initializes the contents to 0. There is a problem here. If T is a non numeric user-defined class, it should be wrong to pass T v=0 as the default parameter of the function, unless the user passes in an instance of this class to replace the default parameter T v=0.

The remaining four overloaded versions of constructors are used for

  1. Copy elements as a whole from an array
  2. Copy elements from an array
  3. Copy elements as a whole from vector < T >
  4. Copy elements between partitions from vector < T >

These four overloaded versions are implemented based on the copyFrom() function (see 2.2).

The final destructor will member variables_ The array object pointed to by elem is delete d [] and the pointer is set to null.

template <typename T>
Vector<T>::Vector(int c, int s, T v) {
    _elem = new T[_capacity = c];
    for (_size = 0; _size < s; ++_size) {
        _elem[_size] = v;
    }
}

template <typename T>
Vector<T>::Vector(T const* A, Rank n) {
    copyFrom(A, 0, n);
}

template <typename T>
Vector<T>::Vector(T const* A, Rank lo, Rank hi) {
    copyFrom(A, lo, hi);
}

template <typename T>
Vector<T>::Vector(Vector<T> const& V) {
    copyFrom(V._elem, 0, V._size);
}

template <typename T>
Vector<T>::Vector(Vector<T> const& V, Rank lo, Rank hi) {
    copyFrom(V._elem, lo, hi);
}


template <typename T>
Vector<T>::~Vector() {
    delete[] _elem;
    _elem = nullptr;
}

2.2 - copy elements from array

Copy the elements between [lo,hi) from array A with protected access rights.
First, create a new (hi - lo) * 2 array, and then copy it one by one.

template <typename T>
void Vector<T>::copyFrom(T const* A, Rank lo, Rank hi) {
    _elem = new T[_capacity = (hi - lo) * 2];
    _size = 0;
    while (lo < hi) {
        _elem[_size++] = A[lo++];
    }
    return;
}

2.3 - overloaded assignment operator=

To facilitate the direct use of = to copy objects, overload = or call the copyFrom() function to copy elements one by one. The access permission is public.

template <typename T>
Vector<T>& Vector<T>::operator=(Vector<T> const& V) {
    if (_elem)
        delete[] _elem;
    copyFrom(V._elem, 0, V._size);
    return *this;
}

2.4 - capacity expansion

When the array space is full, double the capacity, open a new array, copy the original content, and finally release the original space.
After the allocation time complexity analysis, the allocation time complexity of this operation is O(1). The access rights are protected and can only be called when necessary (when inserting elements) in the class.

template <typename T>
void Vector<T>::expand() {
    if (_size < _capacity)
        return;
    if (_capacity < DEFAULT_CAPACITY)
        _capacity = DEFAULT_CAPACITY;
    T* oldElem = _elem;
    _elem = new T[_capacity <<= 1];
    for (int i = 0; i < _size; ++i)
        _elem[i] = oldElem[i];
    delete[] oldElem;
    return;
}

2.5 - volume reduction

Reduce the array space when the attractor is too small. This step is unnecessary for occasions where space requirements are not sensitive. Access rights protected.

template <typename T>
void Vector<T>::shrink() {
    if (_capacity < DEFAULT_CAPACITY << 1)
        return;
    if (_size << 2 > _capacity)
        return;
    T* oldElem = _elem;
    _elem = new T[_capacity >>= 1];
    for (int i = 0; i < _size; ++i)
        _elem[i] = oldElem[i];
    delete[] oldElem;
    return;
}

2.6 - overloaded subscript operator []

In order to directly reference the data items in the vector, the subscript operator [] is overloaded. The access is more intuitive and convenient. The access permission is public.

template <typename T>
T& Vector<T>::operator[](Rank r) const {
    return _elem[r];
}

2.7 - scrambling

Two versions of interval scrambling and overall scrambling are provided.
Scrambling algorithm: from the back to the front, randomly pick one from the front element and exchange it with yourself.
Such an algorithm can ensure that all possible permutations of the same vector are listed uniformly.

template <typename T>
void Vector<T>::unsort(Rank lo, Rank hi) {
    T* V = _elem + lo;
    for (int i = hi - lo; i > 0; --i) {
        swap(V[i - 1], V[rand() % i]);
    }
}

template <typename T>
void Vector<T>::unsort() {
    unsort(0, _size);
}

2.8 - equalizer and comparator

Static function, used only in the current file.

template <typename T>
static bool lt(T const* a, T const* b) {
    return lt(*a, *b);
}

template <typename T>
static bool lt(T const& a, T const& b) {
    return a < b;
}

template <typename T>
static bool eq(T const* a, T const* b) {
    return eq(*a, *b);
}

template <typename T>
static bool eq(T const& a, T const& b) {
    return a == b;
}

2.9 - unordered search

The method of sequential search is adopted.

template <typename T>
Rank Vector<T>::find(T const& e) const {
    return find(e, 0, _size);
}

template <typename T>
Rank Vector<T>::find(T const& e, Rank lo, Rank hi) const {
    while ((lo < hi--) && e != _elem[hi])
        ;
    return hi;
}

2.10 - insertion

template <typename T>
Rank Vector<T>::insert(Rank r, T const& e) {
    expand();
    for (int i = _size; i > r; --i)
        _elem[i] = _elem[i - 1];
    _elem[r] = e;
    _size++;
    return r;
}

template <typename T>
Rank Vector<T>::insert(T const& e) {
    return insert(_size, e);
}

2.11 - delete

Note that contrary to intuition, single element deletion is a special case of interval deletion, remove(r, r + 1);, Instead of iteratively implementing interval deletion with single element deletion, it will bring high time complexity.

template <typename T>
T Vector<T>::remove(Rank r) {
    T e = _elem[r];
    remove(r, r + 1);
    return e;
}

template <typename T>
int Vector<T>::remove(Rank lo, Rank hi) {
    if (lo == hi)
        return 0;
    while (hi < _size)
        _elem[lo++] = _elem[hi++];
    _size = lo;
    shrink();
    return hi - lo;
}

2.12 - unordered vector uniqueness

For the current element, find whether there are duplicate elements in its prefix, and the time complexity is O(n).

template <typename T>
int Vector<T>::deduplicate() {
    int oldSize = _size;
    Rank i = 1;
    while (i < _size) {
        (find(_elem[i], 0, i) < 0) ? ++i : remove(i);
    }
    return oldSize - _size;
}

2.13 - traversal

In the two versions, the function pointer and function object (imitation function) are used for traversal operation respectively.

template <typename T>
void Vector<T>::traverse(void (*visit)(T&)) {
    for (int i = 0; i < _size; ++i) {
        visit(_elem[i]);
    }
    return;
}

template <typename T>
template <typename VST>
void Vector<T>::traverse(VST& visit) {
    for (int i = 0; i < _size; ++i) {
        visit(_elem[i]);
    }
    return;
}

2.14 - count the number of adjacent reverse order pairs

template <typename T>
int Vector<T>::disordered() const {
    int i = 1;
    int count = 0;
    for (i = 1; i < _size; ++i) {
        if (_elem[i - 1] > _elem[i])
            count++;
    }
    return count;
}

2.15 - ordered vector uniqueness

One pointer points to the end of the unique sequence, and the other pointer looks for different elements in the back and append s to the front.

template <typename T>
int Vector<T>::uniquify() {
    Rank i = 0, j = 0;
    while (++j < _size) {
        if (_elem[i] != _elem[j])
            _elem[++i] = _elem[j];
    }
    _size = ++i;
    shrink();
    return j - i;
}

2.16 - find

Perform binary search or Fibonacci search according to the search algorithm specified by the user.

template <typename T>
Rank Vector<T>::search(T const& e, SearchMethod m) const {
    return (_size <= 0) ? -1 : search(e, 0, _size, m);
}

template <typename T>
Rank Vector<T>::search(T const& e, Rank lo, Rank hi, SearchMethod m) const {
    switch (m) {
        case BIN_SEARCH:
            binSearch(_elem, e, lo, hi);
            break;
        case FIB_SEARCH:
            fibSearch(_elem, e, lo, hi);
            break;
        default:
            break;
    }
}

Specific search algorithm:
Fibonacci search algorithm didn't understand very much. The main idea is to improve the dichotomy strategy and use the golden section ratio for division, which can improve the average efficiency.

//When multiple elements hit, the largest rank is returned. When the search fails, the failed location is returned
template <typename T>
static Rank binSearch(T* A, T const& e, Rank lo, Rank hi) {
    while (lo < hi) {
        Rank mi = (lo + hi) >> 1;
        (e < A[mi]) ? hi = mi : lo = mi + 1;
    }
    return --lo;
}

//md can't understand
template <typename T>
static Rank fibSearch(T* A, T const& e, Rank lo, Rank hi) {
    Fib fib(hi - lo);
    while (lo < hi) {
        while (hi - lo < fib.get())
            fib.prev();
        Rank mi = lo + fib.get() - 1;
        if (e < A[mi])
            hi = mi;
        else if (e > A[mi])
            lo = mi + 1;
        else
            return mi;
    }
    return -1;
}

2.17 - sequencer

10 sorting algorithms. The sorting algorithm is selected according to the parameters specified by the user.

template <typename T>
void Vector<T>::sort(Rank lo, Rank hi, SortMethod m) {
    switch (m) {
        case BUBBLE_SORT:
            bubbleSort(lo, hi);
            break;
        case INSERTION_SORT:
            insertionSort(lo, hi);
            break;
        case SHELL_SORT:
            shellSort(lo, hi);
            break;
        case SELECTION_SORT:
            selectionSort(lo, hi);
            break;
        case HEAP_SORT:
            heapSort(lo, hi);
            break;
        case MERGE_SORT_ITERATIVELY:
            mergeSort_iteratively(lo, hi);
            break;
        case MERGE_SORT_RECURSIVELY:
            mergeSort_recursively(lo, hi);
            break;
        case QUICK_SORT:
            quickSort(lo, hi);
            break;
        case COUNTING_SORT:
            countingSort(lo, hi);
            break;
        case RADIX_SORT:
            radixSort(lo, hi);
            break;
        default:
            quickSort();
            break;
    }
    return;
}

template <typename T>
void Vector<T>::sort(SortMethod m) {
    sort(0, _size, m);
}

/*****protected****/

template <typename T>
void Vector<T>::bubbleSort(Rank lo, Rank hi) {
    bool sorted = false;
    while (!sorted) {
        sorted = true;
        for (int i = lo + 1; i < hi; ++i) {
            if (_elem[i - 1] > _elem[i]) {
                swap(_elem[i - 1], _elem[i]);
                sorted = false;
            }
        }
        hi--;
    }
    return;
}

template <typename T>
void Vector<T>::insertionSort(Rank lo, Rank hi) {
    //TODO
    return;
}

template <typename T>
void Vector<T>::shellSort(Rank lo, Rank hi) {
    //TODO
    return;
}

template <typename T>
Rank Vector<T>::max(Rank lo, Rank hi) {
    //TODO
    return 0;
}

template <typename T>
void Vector<T>::selectionSort(Rank lo, Rank hi) {
    //TODO
    return;
}

template <typename T>
void Vector<T>::heapSort(Rank lo, Rank hi) {
    return;
}
template <typename T>
void Vector<T>::mergeSort_iteratively(Rank lo, Rank hi) {
    //TODO
    return;
}

template <typename T>
void Vector<T>::merge(Rank lo, Rank mi, Rank hi) {
    Rank i = 0, j = 0, k = 0;
    T* A = _elem + lo;
    int lb = mi - lo;
    T* B = new T[lb];
    for (i = 0; i < lb; ++i)
        B[i] = A[i];

    T* C = _elem + mi;
    int lc = hi - mi;

    i = 0;
    while ((j < lb) || (k < lc)) {
        if ((j < lb) && (!(k < lc) || B[j] <= C[k]))
            A[i++] = B[j++];
        if ((k < lc) && (!(j < lb) || C[k] < B[j]))
            A[i++] = C[k++];
    }
    delete[] B;
    return;
}

template <typename T>
void Vector<T>::mergeSort_recursively(Rank lo, Rank hi) {
    if (hi - lo < 2)
        return;
    int mi = (lo + hi) / 2;
    mergeSort_iteratively(lo, mi);
    mergeSort_recursively(mi, hi);
    merge(lo, mi, hi);
    return;
}

template <typename T>
Rank Vector<T>::partition(Rank lo, Rank hi) {
    //TODO
    return 0;
}

template <typename T>
void Vector<T>::quickSort(Rank lo, Rank hi) {
    //TODO
    return;
}

template <typename T>
void Vector<T>::countingSort(Rank lo, Rank hi) {
    //TODO
    return;
}

template <typename T>
void Vector<T>::radixSort(Rank lo, Rank hi) {
    //TODO
    return;
}

2.18 - size and space determination

template <typename T>
Rank Vector<T>::size() const {
    return this->_size;
}

template <typename T>
bool Vector<T>::empty() const {
    return !(this->_elem);
}

3 - source code

https://gitee.com/daniel187/dsa_tsu/blob/master/src/Vector.cpp

Keywords: C++ Algorithm data structure STL

Added by glcarlstrom on Wed, 26 Jan 2022 11:27:49 +0200