版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/TailorWu/article/details/80007756
向量vector
#ifndef MYVECTOR_H
#define MYVECTOR_H
typedef int Rank; //秩
#define DEFAULT_CAPACITY 3 //默认的初始容量
template <typename T> //向量魔板类
class myVector{
protected:
Rank _size; //规模
int _capactity; //容量
T* _elem; //数据区
void copyFrom(const T* A, Rank lo, Rank hi); //复制数组区间A
void expand(); //空间不足时扩容
void shrink(); //装填因子过小时压缩
bool bubble(Rank lo, Rank hi); //扫描交换
void bubbleSort(Rank lo, Rank hi); //冒泡排序算法
Rank max(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 heapSort(Rank lo, Rank hi); //堆排序算法
public:
//构造函数
myVector(int c = DEFAULT_CAPACITY, int s = 0, T v = 0){ //容量为c,规模为s,所有元素初始化为v
_elem = new T[_capactity = c];
for (_size = 0; _size< s; ++_size)
{
_elem[_size] = v;
}
}
myVector(const T* A, Rank lo, Rank hi){
comyFrom(A, lo, hi);
}
myVector(T const* A, Rank n) { copyFrom(A, 0, n); } //数组整体复制
myVector(myVector<T> const& V, Rank lo, Rank hi) { copyFrom(V._elem, lo, hi); } //向量区间复制
myVector(myVector<T> const& V) { copyFrom(V._elem, 0, V._size); } //向量整体复制
// 析构函数
~myVector() { delete[] _elem; } //释放内部空间
// 只读访问接口
Rank size() const { return _size; } //觃模
bool empty() const { return !_size; } //刞空
int disordered() const; //刞断向量是否已排序
Rank find(T const& e) const { return find(e, 0, _size); } //无序向量整体查找
Rank find(T const& e, Rank lo, Rank hi) const; //无序向量区间查找
Rank search(T const& e) const //有序向量整体查找
{ return (0 >= _size) ? -1 : search(e, 0, _size); }
Rank search(T const& e, Rank lo, Rank hi) const; //有序向量区间查找
// 可写访问接口
T& operator[](Rank r) const; //重载下标操作符,可以类似于数组形式引用各元素
myVector<T> & operator=(myVector<T> const&); //重载赋值操作符,以便直接克隆向量
T remove(Rank r); //删除秩为r的元素
int 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(*)(T&)); //遍历(使用函数指针,只读或局部性修改)
template <typename VST> void traverse(VST&); //遍历(使用函数对象,可全局性修改)
}; //myVector
#endif
基于赋值的构造方法
- copyFrom()根据待复制区间的边界,换算出新向量的初试规模,再以双倍的容量,为内部数组_elem[]申请空间
- 忽略开辟新空间所需的时间,运行时间应正比于区间宽度,即 O(hi - lo) = O(size)
template <typename T>
void myVector<T>::copyFrom(const T *A, Rank lo, Rank hi) { //以数组区间A[lo,hi)为蓝本复制向量
_elem = new T[_capactity = 2 * (hi-lo)]; //分配空间
_size = 0; //规模清零
while(lo<hi) //逐一复制
_elem[_size++] = A[lo++]; //复制至_elem[0,hi-lo)
}
重载向量赋值操作符
- 防止默认的赋值运算符不足以支持向量之间的直接赋值
template<typename T>
myVector<T>& myVector<T>::operator=(const myVector<T> & V) {
if(_elem)
delete [] _elem; //释放原有内容
copyFrom(V._elem,0,V.size()); //整体复制
return *this; //返回当前对象的引用,以便链式赋值
}
动态空间管理
- 向量实际规模与其内部数组容量的比值(即 _size/_capac)称为装填因子(load factor),他是衡量空间利用率的重要指标
- 扩充向量 :当原数组空间不足时,申请一个容量更大的数组B[ ],并将原数组中的元素全部赋值到新的空间,释放原数组所占的空间
- 一般调用insert()之前都要先调用expand(),检查容量是否能够继续操作
template <typename T>
void myVector<T>::expand() { //向量空间不足时扩容
if (_size < _capactity) return ; //空间充足
if (_capactity < DEFAULT_CAPACITY) _capactity = DEFAULT_CAPACITY; //不低于最小容量
T* oldElem = _elem;
_elem = new T[_capactity <<= 1]; //容量加倍
for (int i = 0; i <_size ; ++i) {
_elem = oldElem[i]; //T为基本类型,或已重载赋值操作符'='
}
delete [] oldElem; //释放原空间
}
- 缩容
template <typename T>
void myVector<T>::shrink() { //装填因子过小时压缩向量所占空间
if (_capactity < DEFAULT_CAPACITY << 1) return;
if (_size << 2 > _capactity) return ; //25%为界
T* oldElem = _elem;
_elem = new T[_capactity >>= 1]; //容量减半
for (int i = 0; i < _size; ++i) { //复制原向量的内容
_elem[i] = oldElem[i];
}
delete [] oldElem; //释放原空间
}
常规使用向量
- 直接引用元素
与数组直接通过下标访问元素的方式相比,使用重载操作符”[ ]”更加自然
template <typename T>
T& myVector<T>::operator [] (myVector::Rank r) const { //重载下标操作符
return _elem[r]; //assert: 0 <= r < _size
}
- 置换器
置乱算法:从待置乱区间的末元素开始,逆序向前逐一处理各元素.
template <typename T>
void myVector<T>::unsort(myVector<T>::Rank lo, myVector<T>::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[rand() % i]); //V[i-1] 与[0,i)中某一元素随机交换
}
}
- 顺序查找(从后往前)
时间复杂度为O(n),最好情况是O(1)
template <typename T> //无序向量的顺序查找:返回最后一个元素e的位置;失败返回lo-1
Rank myVector<T>::find(const T &e, myVector<T>::Rank lo, myVector<T>::Rank hi) const { //assert: 0<=lo < hi <= _size
while((lo < hi--) && (e != _elem[hi])); //从后向前,顺序查找
return hi; //若hi < lo,则意味着失败;否则hi即命中元素的秩
}
- 插入
平均时间复杂度O(n),总体时间复杂度O(_size - r -1)
template <typename T> //将e作为秩为r元素插入
Rank myVector<T>::insert(myVector<T>::Rank r, const T &e) { //assert:0 <=r <= _size
expand();
for (int i = _size; i > r ; --i) {
_elem[i] = _elem[i-1]; //自后向前,后继元素顺次后移一个单元
}
_elem[r] = e;
_size++;
return r; //返回秩
}
- 删除
有两个重载;讲单元素删除视作区间删除的特例,基于后者来实现前者
时间复杂度:O(m+1) ,m为_size-hi+1;
删除单个元素的时间复杂度O(_size-r),位置越靠后,所需时间越短
template <typename T> //删除区间[lo,hi]
int myVector<T>::remove(myVector<T>::Rank lo, myVector::Rank hi) {
if(lo == hi) return 0; //出于效率考虑,单独处理退化情况,比如remove(0,0)
while (hi < _size) //[hi,_size)顺次前移hi -lo 个单元
_elem[lo++] = _elem[hi++];
_size = lo; //更新规模
shrink();
return hi -lo;
}
template <typename T> //删除向量中秩为r的元素,0 <= r < _size
T myVector<T>::remove(myVector<T>::Rank r) {
T e = _elem[r];
remove(r,r+1); //调用区间删除算法,等效于对区间[r,r+1)的删除
return e;
}
- 唯一化
剔除向量中的重复元素
时间复杂度:O(n²)
template <typename T> //删除无序向量中重复元素
int myVector<T>::deduplicate() {
int oldSize = _size;
Rank i = 1; //从_elem[1]开始
while (i < _size) //自前向后逐一考查各元素_elem[i]
(find(_elem[i],0,i) < 0) ? i++ : remove(i); //在其前缀总寻找与之相同者,如无相同继续考查其后继,如有则删除相同者
return oldSize - _size;
}
- 遍历
template <typename T> //利用函数指针的机制遍历
void myVector<T>::traverse(void (*visit)(T &)) {
for (int i = 0; i < _size; ++i) {
visit(_elem[i]);
}
}
template <typename T>
template <typename VST>
void myVector<T>::traverse(VST& visit) {
for (int i = 0; i < _size; ++i) {
visit(_elem[i]);
}
}
有序向量
- 有序性甄别
template <typename T> //返回向量中逆序相邻元素的总数
int myVector<T>::disordered() const {
int n = 0;
for (int i = 0; i < _size; ++i) {
if(_elem[i-1] > _elem[i]) //逐一检查_size -1对相邻元素
++n;
}
return n; //如果n为0即为有序
}
- 唯一化
针对有序向量进行,时间复杂度为O(n),基本是最优解
template <typename T> //有序向量重复元素剔除(高效)
int myVector<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; //向量规模变化量,被删除元素总数
}
- 查找
当有序向量中元素互异时,秩r即是S中小于S[r]的元素项目
一般情况时,若小于,等于S[r]的元素各有i,k个,则该元素及其雷同元素应集中分布于S[i,i + k)
template <typename T> //在有序向量的区间[lo,hi)内,确定不大于e的最后一个节点的秩
Rank myVector<T>::search(const T &e, int lo, int hi) const { //assert: 0 <= lo < hi <= _size
//按各50%的概率随机使用 二分查找或Fibonacci查找
return (rand() % 2)? binSearch(_elem,e,lo,hi) : fibSearch(_elem,e,lo,hi);
}
- 二分查找
时间复杂度为O(log(n))
/ /二分查找(版本A):在有序向量的区间[lo,hi)内查找元素e, 0 <= lo <= hi <= _size
static Rank binSerach(T* A,const T& 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; //查找失败
//有多个命中元素时,不能保证返回秩最大/最小者;
//查找失败时简单返回-1,不能指示最后失败的位置
}
来自于<<数据结构–C++语言描述>> 邓俊辉 第二章