《数据结构邓版》学习笔记-第二章vector

本文介绍了一个通用向量容器的实现细节,包括构造、赋值、动态调整大小等核心功能,以及排序、查找、删除等实用算法。这些算法适用于C++等支持泛型编程的语言。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码2.2 基于赋值的向量构造器

copyFrom()首先根据待复制区间的边界,换算初新向量的初始规模;再以双倍的容量,为内部数组_elem[]申请空间。最后通过一趟迭代,完成区间A[lo, hi]内各元素的顺次复制。

template<typename T>

void Vector<T>::copyForm(T const* A, Rank o, Rank hi)

{

    _elem = new T[_capacity = 2 * (hi - locale)];

    _size = 0;

    while (lo < hi)

        _elem[_size++] = A[lo++];

}

代码2.3重载向量赋值操作符

operator=()首先释放原有内容,然后再整体复制,最后返回当前对象的引用。

template<typename T>

Vector<T>& Vector<T>::operator=(Vector<T> const& V)

{

    if (_elem)

        delete[]_elem;

    copyForm(V._elem, 0, V.size());

    return *this;

}

代码2.4 向量内部数组动态扩容算法expand()

Expand()首先判断是否满员,再判断是否低于默认容量,然后是容量加倍,然后是复制原向量内容,最后是释放原空间。

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;

}

代码2.5 向量内部功能shrink()

Shrink()实现步骤与expand()类似,当空间利用率已降至某一阀值以下,就立即申请一个容量减半的新数组,将原数组的元素逐一搬迁至其中,最后将原数组所占空间交还操作系统。

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;

}

代码2.6 重载向量操作符[]

template <typename T>

T& Vector<T>::operator[](Rank r)const

{

    return _elem[r];

}

代码2.7 向量整体置乱算法permute()

permute()算法从待置乱区间的末元素开始,逆序地向前逐一处理各元素。

template <typename T>

void permute(Vector<T>& V)

{

    for (int i = V.size(); i > 0; i--)

        swap(V[i - 1], V[rand() % i]);

}

代码2.8 向量区间置乱接口unsort()

unsort()均匀的置乱lo,hi区间内的元素,整体套用permute函数。

template<typename T>

void Vector<T>::unsort(Rank lo, Rank hi)

{

    T* V = _elem + lo;

    for (Rank i = hi - lo; i > 0; i--)

        swap(V[i - 1], V[rand() % i]);

}

代码2.10 无序向量元素查找接口find()

find()自后向前,顺序查找,返回hi,要么失败,要么返回hi命中的元素。

template<typename T>

Rank Vector<T>::find(T const& e, Rank lo, Rank hi)const

{

    while ((lo < hi--) && (e != _elem[hi]));

    return hi;

}

代码2.11 向量元素插入接口insert()

Insert()负责将任意给定的元素e插入到任意指定的秩为r的单元。首先判断是否将要移出,若有必要,扩容。然后自后向前,顺序后移一个单元,再将新元素放入r的位置的变量,并更新容量,最后返回秩。

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;

}

代码2.12 向量区间删除接口remove()

remove()首先单独处理退化情况。再将[hi, _size]顺次前移hi – lo个单元,然后更新规模,直接丢弃尾部[lo, _size = hi)区间。有必要就缩容。最后返回被删减元素的数目。

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.13 向量单元素删除接口remove()

remove()首先备份被删除的元素,然后调用区间删除算法,等效于对区间[r, r+ 1]的删除,返回被删除元素。

template<typename T>

T Vector<T>::remove(Rank r)

{

    T e = _elem[r];

    remove(r, r + 1);

    return e;

}

代码2.14 无序向量清除重复元素接口deduplicate()

Deduplicate()函数自前向后逐一考查各元素_elem[i],并通过调用find()接口,查找雷同者,找到就调用remove()删除,最后就返回被删除元素总数。

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.15 向量遍历接口traverse()

traverse()借助函数指针或函数对象自前向后组逐一对各元素实施同一基本操作。

template<typename T>

void Vector<T>::traverse(void (*visit)(T&))

{

    for (int i = 0; i < _size; i++)

        visit(_elem[i]);

}

template<typename T>

template<typename VST>

void Vector<T>::traverse(VST& visit)

{

    for (int i = 0; i < _size; i++)

        visit(_elem[i]);

}

代码2.16 基于遍历实现increase()功能

设立一个函数对象,里面只有一个operator()函数,然后设立一个increase()函数调用traverse()函数。

template<typename T>

struct Increase

{

    virtual void operator()(T& e)

    {

        e++;

    }

};

template<typename T>

void increase(Vector<T>& V)

{

    V.traverse(Increase<T>());

}

代码2.17 有序向量甄别算法disordered()

disordered()函数首先设立一个计数器,然后逐一检查_size – 1 对相邻元素,如果逆序则计数,最后返回计数值。

template<typename T>

int Vector<T>::disordered()const

{

    int n = 0;

    for (int i = 1; i < _size; i++)

        if (_elem[i - 1] > _elem[i])

             n++;

    return n;

}

代码2.18 有序向量uniquify()接口的平凡实现

自前向后,逐一对比各对相邻元素,若相同就删除后者,否则转至下一元素,最后返回变化的规模。

template<typename T>

int Vector<T>::uniquify()

{

    int oldSize = _size;

    int i = 1;

    while (i < _size)

        _elem[i - 1] == _elem[i] ? remove(i) : i++;

    return oldSize - _size;

}

代码2.19 有序向量uniquify()接口的高效实现

首先初始化两个表示位,组逐一扫描,直到末元素,其中若发现相同者,就跳过,否则就向前移至前者右侧。最后更新_size, shrink(),返回被删除元素总数。

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.20 有序向量各种查找算法的统一search()接口

主要是随机判断调用binSearch()还是fibSearch()函数。

template<typename T>

Rank Vector<T>::search(T const& e, Rank lo, Rank hi)const

{

    return (rand() % 2) ? binSearch(_elem, e, lo, hi) : fibSearch(_elem, e, lo, hi);

}

代码2.21 二分查找版本A

在有序向量区间[lo, hi)内查找e,该算法以中点mi为界,判断比较,最后失败返回-1,成功返回mi。

template<typename T>

static Rank binSearch(T* A, T const& e, Rank lo, Rank hi)

{

    while (lo < hi)

    {

        Rank mi = (lo + hi) >> 1;

        if (e < A[mi])

             hi = mi;

        else if (A[mi] < e)

             lo = mi + 1;

        else

             return mi;

    }

    return -1;

}

代码2.22 Fibonacci查找算法

需要有之前的fibonacci类。具体要自己分析。

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 (A[mi] < e)

             lo = mi + 1;

        else

             return mi;

    }

    return -1;

}

代码2.23 二分查找版本B

于版本A在于划分不同,[lo, mi)和[mi, hi]。

template<typename T>

static Rank binSearch(T* A, T const& e, Rank lo, Rank hi)

{

    while (1 < hi - lo)

    {

        Rank mi = (lo + hi) >> 1;

        (e < A[mi]) ? hi = mi : lo = mi;

    }

    return (e == A[lo]) ? lo : -1;

}

代码2.24 二分查找版本C

和版本B在于失败时返回的值是不大于e的最大秩。

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;

}

代码2.25 向量排序器接口

随机选取一种排序函数。

template<typename T>

void Vector<T>::sort(Rank lo, Rank hi)

{

    switch (rand() % 5)

    {

    case 1: bubbleSort(lo, hi);

        break;

    case 2: selectionSort(lo, hi);

        break;

    case 3:mergeSort(lo, hi);

        break;

    case 4:heapSort(lo, hi);

        break;

    default: quickSort(lo, hi);

        break;

    }

}

代码2.26 向量的气泡排序

将bubble集成到bubbleSort里面。

template<typename T>

void Vector<T>::bubbleSort(Rank lo, Rank hi){

    while (!bubble(lo, hi--));

}

代码2.27 单躺扫描交换

主要相对于之前的bubbleSort加入了flag位,主要其减少时间复杂度。与代码2.26结合使用。

template<typename T>

bool Vector<T>::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;

}

代码2.28 向量的归并排序

主要是采用归并算法是递归算法,有递归基,以中点为界不断划分,然后分别排序,最后合并。

template<typename T>

void Vector<T>::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);

}

代码2.29 有序向量的二路归并

首先定义合并后的向量A[0, hi – lo),定义前子向量B[0, lb),在复制前子向量,同理定义后子向量C。然后判定B和C中的小者复制到A里面,最后删除临时空间。

template<typename T>

Rank Vector<T>::merge(Rank lo, Rank mi, Rank hi)

{

    T* A = _elem + lo;

    int lb = mi - lo;

    T* B = new T[lb];

    for (Rank i = 0; i < lb; B[i] = A[i++]);

    int lc = hi - mi;

    T* C = _elem + mi;

    for (Rank i = 0, j = 0, k = 0; (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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值