数据结构与算法之-----向量(Vector)

        写在前面的话:本专栏的主要内容:数据结构与算法。

        1.对于​​​​​​​初识数据结构的小伙伴们,鉴于后面的数据结构的构建会使用到专栏前面的内容,包括具体数据结构的应用,所使用到的数据结构,也是自己构建的,未使用系统的库文件,因此,建议这类小伙伴们从本专栏的总揽​​​​​​​按顺序进行学习

        ​​​​​​​2.对于想查询有关资料的小伙伴们,可以选择性地浏览。希望小伙伴们都能有所收获~

 ​  ​​​​​​   

本章的主要内容:数据结构之-----向量

        数据结构中最基础也是最重要的一个数据结构----向量笔者大学所学的数据结构貌似与当前流行的学习内容有些不同,如果将数据按逻辑结构来简单划分的话,可以分为线性结构非线性结构线性结构里有一个顺序表的概念,其实,您可以把向量看成是顺序表的实例,下面我们来看向量的C++实现:

        先来看头文件,头文件中的内容非常之多,基本囊括了向量中大部分的知识,包括多种查询算法,插入算法,删除算法等等,为了代码的高可用性,笔者使用了模版类,如果您对于某段代码不太理解,可以先放一放,去查询一下相关资料,此外,如果代码中有错误之处,敬请指出,谢谢!


/*
 * 作者:易果啥笔
 * 时间:2021.8.18
 * 内容:向量模板类的头文件
 *
 */

#ifndef VECTOR_VECTOR_H
#define VECTOR_VECTOR_H
#include 
#include "Vector.h"
#include 
using namespace std;

typedef int Rank;  //秩
#define DEFAULT_CAPACITY 3   //默认的初始容量




template 
class Vector    {   //向量模板类
    protected:
        Rank _size{} ; int _capacity{} ; T* _elem ; //规模,容量,数据区
        void copyForm(T const* A , Rank lo , Rank hi) ; //复制数组区间A[lo,hi)
    	void expand() ; //空间不足时扩容
        void shrink() ; //装填因子过小时压缩
        bool bubble(Rank lo , Rank hi) ; //扫描交换
        void swap(T& e1,T& e2) ; //交换元素
        void bubbleSort(Rank lo , Rank hi) ; //起泡排序算法
        void selectionSort(Rank lo , Rank hi) ; //选择排序算法
        void merge(Rank lo ,Rank mi, Rank hi) ; //归并算法
        void mergeSort(Rank lo,Rank hi) ; //归并排序算法
        Rank partition(Rank lo , Rank hi) ; //轴点构造算法
        void quickSort(Rank lo , Rank hi) ; //快速排序算法
        void insertionSort(Rank lo , Rank hi) ; //插入排序算法

    public:
        //构造函数
        explicit Vector(int c = DEFAULT_CAPACITY , int s = 0 , T v = 0){
            _elem = new T[_capacity  = c] ;
            for (_size = 0 ; _size < s ; _elem[_size++] = v);
            
        } //容量为c,规模为s,所有元素初始为v
        Vector(T const* A , Rank lo , Rank hi){
            copyForm(A,lo,hi) ; //数组区间复制
        }
        Vector(T const* A , Rank n){
            copyForm(A,0,n) ; //数组整体复制
        }
        Vector(Vector const* V , Rank lo , Rank hi){
            copyForm(V->_elem,lo,hi) ; //向量区间复制
        }
        Vector(Vector const* V){
            copyForm(V->_elem,0,V->_size) ; //向量整体复制
        }

        //析构函数
        ~Vector(){ delete [] _elem ; } //释放内部空间

        //只读访问接口
        Rank size() const {return _size ; } //规模
        bool isEmpty() const {return _size;} //判空
        int disordered() const ; //判断向量是否已排序
        Rank find(T const& e) const {return find(e,0,(Rank)_size) ; } //无序向量整体查找
        Rank find(T const& e , Rank lo , Rank hi) const ; //无序向量区间查找
        Rank search(T const& e ) const {return (0 >= _size) ? -1 : search(e,(Rank)0,(Rank)_size) ; } //有序向量整体查找
        Rank search(T const& e , Rank lo , Rank hi) const ; //有序向量区间查找

        //可写访问接口
        T& operator[](Rank r) const ; //重载[]运算符,可以类似数组形式引用各元素
        Vector & operator=(Vector const&) ; //重载赋值操作符,以便直接克隆向量
        T remove(Rank r) ; //删除秩为r的元素
        Rank remove(Rank lo , Rank hi) ; //删除秩在[lo,hi)之内的元素

        Rank insert(Rank r , T const& e) ; //插入元素
        Rank insert(T const& e) {return insert(_size,e) ; } //默认作为末元素插入
        void sort(Rank lo , Rank hi) ; //对[lo,hi)排序
        void sort() {sort(0,_size) ; } //整体排序
        void unsort(Rank lo , Rank hi) ; //对[lo,hi)置乱
        void unsort() {unsort(0,_size) ; } //整体置乱
        int deduplicate() ; //无序去重
        int uniquify() ; //有序去重

        //遍历
        void traverse(void (* visit)(T&)); //遍历(使用函数指针,只读或局部性修改)
        //template void traverse(VST &) ; //遍历(使用函数对象,可全局性修改)


}; // Vector



/*
 *
 * 静态方法
 *
 *
 */



//Fibonacci数列的构造
template  static void fibonacci(T *f,int MAXSIZE)
{
    f[0] = 0;
    f[1] = 1;
    for(int i = 2;i < MAXSIZE;++i)
        f[i] = f[i - 2] + f[i - 1];
}





/*
 *
 * protected方法
 *
 */



template   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 ;
} //查找失败时,能指示失败的位置



template   Rank fibSearch(T* A,T const& e,Rank lo,Rank hi){
    Rank n = hi-lo , k = 0 , *array;
    array = new T[n] ;
    fibonacci(array,n) ;
    while(n > array[k] - 1) //计算出n在斐波那契中的数列
        ++k;
    for(int i = n ; i < array[k] - 1 ; ++i) //把数组补全
        array[i] = array[n-1];
    while(lo < hi){
        Rank mi = lo + array[k-1] - 1 ; //找轴点
        if(e  void Vector::copyForm(const T *A, Rank lo, Rank hi) {
    _elem = new T[_capacity = (hi-lo)<<1] ; _size = 0 ;//分配空间,规模清零
    while(lo < hi)
        _elem[_size++] = A[lo++] ; //复制至_elem[0,hi-lo)
}

template  void Vector::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] ; //复制原向量内容(T为基本类型,或已经重载赋值操作符"=")
    delete [] oldElem ; //释放原空间
}

template  void Vector::shrink() { //装填因子过小时压缩向量所占空间
    if(_capacity < DEFAULT_CAPACITY << 1) return; //不至于收缩到DEFAULT_CAPACITY以下
    if(_size << 2 > _capacity) return; //以25%为界
    T* oldElem = _elem ; _elem = new T[_capacity >>= 1] ; //容量减半
    for(int i = 0 ; i< _size ; i++) {_elem[i] = oldElem[i];}//复制原向量内容
    delete [] oldElem ;
}

template void Vector::swap(T &e1, T &e2) {
    int temp ;
    temp = e1 ;
    e1 = e2 ;
    e2 = temp ;

}


template bool Vector::bubble(Rank lo, Rank hi) { //一趟扫描交换
    bool sorted = true ;
    while (++lo < hi)
        if(_elem[lo-1] > _elem[lo]){
            sorted = false ;
            swap(_elem[lo-1],_elem[lo]) ; //通过交换使局部有序
        }
    return sorted ; //返回有序标志
}

template void Vector::bubbleSort(Rank lo, Rank hi) {
    while (!bubble(lo,hi--)) ; //逐趟做扫描交换,直至全序
}

template void Vector::selectionSort(Rank lo, Rank hi) {
    while(lo < hi){
        Rank temp = lo ;
        for(Rank i = lo+1 ; i < hi ; i++){
            if(_elem[temp] > _elem[i]) temp = i ;
        }
        swap(_elem[lo++],_elem[temp]) ;
    }
}

template void Vector::insertionSort(Rank lo , Rank hi) {
    for(int i = 0 ; i < hi - lo ; i++){
        insert(binSearch(_elem,_elem[lo],lo-i,lo)+1,_elem[lo]);
        lo++ ; remove(lo--) ;
    }
}



template void Vector::merge(Rank lo, Rank mi, Rank hi) { //有序向量的归并,以mi为界,各自有序的子向量[lo,mi)和[mi,hi)
    T* A = _elem + lo ; //合并后的向量A[0,hi - lo) = _elem[lo,hi)
    int lb = mi - lo ; T* B = new T[lb] ; //前子向量B[0,lb) = _elem[lo,mi)
    for(Rank i = 0 ; i < lb ; i++)
        B[i] = A[i] ; //复制前子向量
    int lc = hi - mi ; T* C = _elem + mi ; //后子向量C[0,lc) = _elem[mi,hi)
    for(Rank i = 0 , j = 0 , k = 0 ; (j < lb) || (k < lc) ; ){ //将B[j]和C[k]中的小者续至A末尾
        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 ;
}

template void Vector::mergeSort(Rank lo, Rank hi) { //向量归并排序
    if (hi - lo < 2) return ;
    int mi = (lo + hi) >> 1 ; //以中点为界
    mergeSort(lo,mi) ; mergeSort(mi,hi) ; merge(lo,mi,hi) ; //分别对前后半段排序,然后归并
}


template Rank Vector::partition(Rank lo, Rank hi) { //轴点构造算法:通过调整元素位置构造区间[lo,hi]的轴点,并返回其秩
    swap(_elem[lo],_elem[lo + rand() % (hi -lo +1)]) ; //任意一个元素与首元素交换
    T pivot = _elem[lo] ; //以首元素为候选轴点-----经以上交换,等效于随机选取
    while(lo < hi){ //以向量的两端交替地向中间扫描
        while((lo < hi))
            if(pivot < _elem[hi]) //在大于的pivot前提下
                hi--; //向左扩展右端子向量
            else //直至遇到不大于pivot者
            {_elem[lo++] = _elem[hi] ; break ;} //将其归入左端子向量
        while ((lo < hi))
            if(_elem[lo] < pivot)
                lo++;
            else
                {_elem[hi--] = _elem[lo] ; break ;}
    }
    _elem[lo] = pivot ; //将备份的轴点记录置于前,后子向量之间
    return lo ; //返回轴点的秩

}


template void Vector::quickSort(Rank lo, Rank hi) {
    if(hi - lo < 2) return ;
    Rank mi = partition(lo,hi - 1) ;
    quickSort(lo,mi) ;
    quickSort(mi + 1,hi) ;
}



/*
 *
 * public方法
 *
 */



template  Vector& Vector::operator=(const Vector & V) {
    if(_elem) delete [] _elem ; //释放原有内容
    copyForm(V._elem,0,V.size()) ; //整体复制
    return *this ; //返回当前对象的引用,以便链式赋值
}

template  T& Vector::operator[](Rank r) const {
    return _elem[r] ; // 0 <= r < _size
}


template  void Vector::unsort(Rank lo, Rank hi) {
    T* V = _elem + lo ; //将子向量_elem[lo,hi)视作另一向量V[0,hi-lo)
    for(Rank i = hi - lo ; i > 0 ; i--) //自后向前
        swap(V[i-1],V[random() % i]) ; //V[i - 1]与V[0 , i]中某一随机元素交换

}

template  Rank Vector::find(const T &e, Rank lo, Rank hi) const {
    while((lo < hi--) && (e != _elem[hi])) ; //从后向前,顺序查找
    return hi ; //若hi < lo,则意味着失败,否则将返回hi即为命中元素的秩
}

template  Rank Vector::insert(Rank r, const T &e) {
    expand() ; //若有必要,扩容
    for(int i = _size ; i > r ; i--) _elem[i] = _elem[i-1] ; //自后向前,后继元素顺次后移一个单元
    _elem[r] = e ; _size++ ; //置入新元素并更新容量
    return r ; //返回秩
}

template  Rank Vector::remove(Rank lo, Rank hi) {
    if(lo == hi) return 0 ; //出于效率考虑,单独处理退化情况,比如remove(0,0);
    while(hi < _size) _elem[lo++] = _elem[hi++] ; //[hi,_size)顺次前移hi-lo个单元
    _size = lo ; //更新规模,直接丢弃尾部[lo,_size = hi)区间
    shrink() ; //若有必要,则缩容
    return hi - lo ; //返回被删除的元素个数
}

template  T Vector::remove(Rank r) {
    T e = _elem[r] ; //备份被删除元素
    remove(r,r+1) ; //调用区间删除算法,等效于对区间[r,r+1)的删除
    return e ; //返回被删除的元素
}

template  Rank Vector::deduplicate() {
    int oldSize = _size ; //记录原规模
    Rank i = 1 ; //从_elem[1]开始
    while(i < _size)
        ( find(_elem[i] , 0 , i) < 0) ? //在其前缀中寻找与之雷同者(至多一个)
        i++ : remove(i) ; //若无雷同者则继续考察其后继,否则就删除雷同者
    return oldSize - _size ; //返回被删除元素的总数
}

template  void Vector::traverse(void (*visit)(T &)) {
    for(int i = 0 ; i < _size ; i++) visit(_elem[i]) ; //利用函数指针机制的遍历
}

//template  template 
//Rank Vector::traverse(VST & visit) {
   //for(int i = 0 ; i < _size ; i++) visit(_elem[i]) ; //利用函数对象机制的遍历
//}

template  int Vector::disordered() const {
    int n = 0 ; //计数器
    for(int i = 1 ; i < _size ; i++) //逐一检查_size-1对相邻元素
        if(_elem[i-1] > _elem[i]) n++ ; //逆序则计数
    return n ; //向量有序但且仅当n=0
}

template  Rank Vector::uniquify() {
    Rank i = 0 , j = 0 ; //各对互异"相邻"元素的秩
    while(++j < _size) //逐一扫描,直至末元素
        if(_elem[i] != _elem[j]) //跳过雷同者
            _elem[++i] = _elem[j] ; //发现不同元素时,向前移至紧邻于前者右侧
    _size = ++i ; shrink() ; //直接截除尾部多余元素
    return  j-1 ; //返回被删除元素总数
}

template  Rank Vector::search(const T &e, Rank lo, Rank hi) const {
    return (random()%2) ?
        binSearch(_elem,e,lo,hi) : fibSearch(_elem,e,lo,hi) ; //Fibonacci查找
}

template void Vector::sort(Rank lo, Rank hi) {

    switch (random() % 4) { //随机选择排序算法,可根据问题的特点灵活选取或扩充
        case 1 : bubbleSort(lo,hi) ; break ; //起泡排序
        case 2 : selectionSort(lo,hi) ; break ; //选择排序
        case 3 : mergeSort(lo,hi) ; break ; //归并排序
        case 4 : insertionSort(lo,hi); //插入排序
        default: quickSort(lo,hi) ; break ; //快速排序
    }



}



#endif //VECTOR_VECTOR_H

        在头文件里,我们定义了向量的一些基本运算,下面,我们以一个main文件来展示向量的基本操作:


/*
 * 作者:易果啥笔
 * 时间:2021.8.18
 * 内容:Vector模版类的应用
 *
 */


#include 
#include "Vector.h"
#include 
#include 

#define CAPACITY 10
#define SIZE 5
#define VALUE 0


using namespace std;

template void print(T a){
    std::cout< vector(CAPACITY,SIZE,VALUE);
    vector[0] = 1 ;
    vector[1] = 2 ;
    vector.insert(2,3);
    vector.insert(3,7);
    vector[4] = 1 ;
    //遍历
    vector.traverse(print);
    
    vector.sort();cout<

        main文件中,笔者使用了C++中的ctime库中的clock_t对象来测试向量的一些基本操作的耗时,读者可以忽略。

        下一篇:数据结构与算法之-----链表​​​​​​​

你可能感兴趣的:(数据结构与算法,数据结构,算法)