【数据结构与算法】dsa之C++实现向量代码Vector<T>

一、尊敬的邓公的课程网址

学好《数据结构与算法·C++》-清华大学邓俊辉老师。所有的课件视频资料都在这里数据结构(C ++语言版),包括:

  • 课程书籍
  • 习题集
  • dsacpp即,源代码
  • 讲义、课件
  • 甚至提交作业的网站

向量数据结构的实现

以下代码全为学习后手码,包括但不限于:
  • 有序向量
  • 无序向量
  • 二分查找
  • 斐波那契查找
  • 起泡排序
  • 归并排序
  • 选择排序

1. Vecter.h头文件

之前文件名错写成Vecter,应该是Vector,代码中已经改正

#pragma once
typedef int Rank;//秩
#define DEFAULT_CAPACITY 8//设置默认容量为3

template <class T> class Vector//向量模板类
{
public:
//构造函数
	Vector(int c = DEFAULT_CAPACITY, int s = 0, T v = 0) {//容量为c、规模为s、所有元素初始为v
		_elem = new T[_capacity = c]; for (_size = 0; _size < s; _elem[_size++] = v);}
	Vector(T const* A, Rank n) { copyFrom(A, 0, n); }//数组整体A[0,n]复制
	Vector(T const* A, Rank lo, Rank hi) { copyFrom(A, lo, hi); }//数组区间复制
	Vector(Vector<T> const& V) { copyFrom(V._elem, 0, V._size); }//向量整体复制
//析构函数
	~Vector() { 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); } // 有序向量整体查找,search的特殊语义约定:返回不大于e且秩最大的元素
	Rank search(T const& e, Rank lo, Rank hi) const;//有序向量区间查找

//可写访问接口
	T& operator[](Rank r)const { return _elem[r]; }//重载下标操作符,可以类似与数组形式引用个元素
	Vector<T>& operator=(Vector<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 (*visit)(T&));//遍历:使用函数指针,只读或者局部性修改
	template<typename VST> void traverse(VST&);//遍历(使用函数对象,可全局性修改)
protected:
	Rank _size; int _capacity; T* _elem;//向量Vector的规模、容量、数据区
	void copyFrom(T const* A, Rank lo, Rank hi);//复制数组区间A[lo,hi]
	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);//堆排序
};//Vector

2.斐波那契头文件

斐波那契数列头文件,仅仅是斐波那契二分查找下的黄金分割算法需要这个文件。

#pragma once

class Fib { //Fibonacci数列类
private:
	int f, g; //f = fib(k - 1), g = fib(k)。均为int型,很快就会数值溢出
public:
	Fib(int n) //初始化为不小于n的最小Fibonacci项
	{
		f = 1; g = 0; while (g < n) next();
	} //fib(-1), fib(0),O(log_phi(n))时间
	int get() { return g; } //获取当前Fibonacci项,O(1)时间
	int next() { g += f; f = g - f; return g; } //转至下一Fibonacci项,O(1)时间
	int prev() { f = g - f; g -= f; return g; } //转至上一Fibonacci项,O(1)时间
};

3.Vector.cpp源文件

#include "Vecter.h"
#include <iostream>
#include "Fib.h"
using namespace std;//swap,cout等函数
//判等器(对比)和比较器(比较)
template<class T> static bool lt(T* A, T* B) { lt(A, B); }
template<class T> static bool lt(T& A, T& B) { A < B; }//less than,A比B小?
template<class T> static bool eq(T* A, T* B) { eq(A, B); }
template<class T> static bool eq(T& A, T& B) { A = B; }//equal

template<class T> Vector<T>& Vector<T>::operator=(Vector<T> const& V) {
	if (_elem) delete[] _elem;
	copyFrom(V._elem);
	return *this;//返回this指针(当前对象),以便链式赋值
}
template<class T> void Vector<T>::copyFrom(T const* A, Rank lo, Rank hi) {//基于复制的构造方法
	_elem = new T[_capacity = 2 * (hi - lo)]; _size = 0;//分配两倍容量,规模清零
	while (lo < hi)//约定:数组A[lo,hi)
		_elem[_size++] = A[lo++];//特别注意此时的lo++是,先取Rank空间再对lo = lo+1
}
template<class T> void Vector<T>::expand() {
	if ( _size < _capacity) return;//尚未满员时,无需扩容
	if (_capacity < DEFAULT_CAPACITY) _capacity = DEFAULT_CAPACITY;//保障不低于最小容量
	//下处的处理非常聪明的地方在于:数组的迁移,使用指针这一技巧,改变了指向。
	T* oldelem = _elem; _elem = new T[_capacity<<=1]; //两倍扩容,二进制下左移一位,即为乘以2
	for (int i = 0; i < _size; i++) {
		_elem[i] = oldelem[i];}//复制原向量内容,或已经重载【operator=】的前提下
	delete[] oldelem;//释放原空间
}
template<class T> void Vector<T>::shrink() {//装填因子过小时压缩,本代码中约定装填不足25%
	if (_capacity < _capacity << 1) return; //不至于收缩到默认二倍容量以下,上界
	if (_size << 2 > _capacity) return;//以25%为界,下界
	T* oldelem = _elem; _elem = new T[_capacity >>= 2];//容量减半
	for (int i = 0; i < _size; i++) {
		_elem[i] = oldelem[i];
	}
	delete[] oldelem;//除了上下界,与扩容是对称的
}
template<class T> void permute(Vector<T> V) {//随机置乱向量,使各元素等概率出现于各位置
	for (int i = V.size(); i > 0; i--) {
		swap(V[i - 1], V[rand() % i]);//一般性:rand() % (b-a+1)+ a ;b=i-1.就表示  a~b 之间的一个随机整数。
	}
}//置乱算法,算法原理但是不属于Vector
template<class T> void Vector<T>::unsort(Rank lo,Rank hi) {
	T* V = _elem + lo;//把_elem看作指针,指向的是一组连续数组空间,加lo之后仅仅只有指针位置变化
	                  //数组的内容不变,也就是此时V指向的是_elem[lo]这个元素
					  //V数组的真实长度变为V[0,hi-lo],内容变为_elem[lo,hi],(不过也可能比hi长)
	for (int i = hi - lo; i > 0; i--) {
		swap(V[i - 1],V[rand() % i]); 
	}
}//区间置乱接口
template <class T> Rank Vector<T>::find(T const&e, Rank lo, Rank hi) const{
	while ((lo < hi--) && (e != _elem[hi]));//先判断再自减,和之前的copyFrom函数[lo++]同理
	return hi; //若未找到返回lo-1
}
template <class T> Rank Vector<T>::insert(Rank r, T const& e) {
	expand();
	for (int i = _size; i > r; i--) _elem[i] = _elem[i - 1];//自后向前,由于C++是[lo,hi),所以_size=hi
	_elem[r] = e; _size++;//置入新元素并更新容量
	return r;//返回秩
}
template <class T> T Vector<T>::remove(Rank r) {
	T oldelem = _elem[r];
	remove(r, r + 1);
	return oldelem;
}//实际可行的思路恰好相反
template <class T> int Vector<T>::remove(Rank lo, Rank hi) {
	if (lo = hi)return 0;
	while (hi < _size)_elem[lo++] = _elem[hi++];
	_size = lo;//size= 现在的lo
	shrink();
	return hi - lo;
}
//唯一化,视向量是否有序,该功能有两种实现方式
//方式一:无序向量,O(n^2)
template<class T> int Vector<T>::deduplicate() {
	int oldsize = _size;
	Rank i = 1;
	while (i<_size) (find(_elem[i], 0, i) ) < 0 ? i++ : remove(i);//666
	//此步骤的证明在书本P42·图2.6中
	//复杂度为n^2
	//明智之举在于,只需要保证前缀中所有元素彼此互异的不变性即可
	return oldsize - _size;//remove函数中改变了_size函数
}
//方式二:有序向量,O(n)
template<class T> int Vector<T>::uniquify() {
	Rank i = 0, j = 0;
	while (++j < _size)
		if (_elem[i] != _elem[j])
			_elem[++i] = _elem[j];//规律:只要是++i/i++遇到其他的运算符,用赋值运算符来记忆
								  //=++i,先加一再赋值;=i++,先赋值再加一
								  //结论:++前缀先算,++后缀后算
	_size = ++i; shrink();
	return j - i;
}
//遍历:将向量看作一个整体,对其中所有元素实施某种统一的操作
//例如:输出向量中所有的元素,或者按照某种运算流程统一修改所有元素的数值
//方式一:《DSA·第三版》P43,没太懂
template<class T> void Vector<T>::traverse(void (*visit)(T&)) {//借助函数指针机制
	for (int i = 0; i < _size; i++) visit(_elem[i]);}
//方式二:《DSA·第三版》P43,没太懂
template<typename T> template<typename VST>//元素类型、操作器
void Vector<T>::traverse(VST& visit)
{ for (int i = 0; i < _size; i++) visit(_elem[i]); }

template<class T> int Vector<T>::disordered() const {//有序性甄别
	int n = 0;//计数器
	for (int i = 1; i < _size; i++) if (_elem[i-1] > _elem[i]) n++;//从i=1开始,防止越界
	return n;
}
二分查找,版本A
//template<class T> Rank binSearch(T &_elem, T e, Rank lo, Rank hi) {
//	while (lo<hi){
//		Rank mi = (lo + hi) >> 1;
//		if (e < _elem[mi]) hi = mi;
//		else if (_elem[mi] < e) lo = mi + 1;
//		else return mi;}
//	return -1;//无法严格按照语义执行
//}
二分查找,版本B
//template<class T> Rank binSearch(T& A, T e, Rank lo, Rank hi) {
//	while (1 < hi - lo) {
//		Rank mi = (hi + lo) >> 1;//以中点为轴点,因此是+号
//		(e < A[mi] )? hi = mi : lo = mi;}
//	return ( A[lo] == e )? lo : -1;//无法严格按照语义执行
//}
//二分查找,版本C
template<class T> Rank binSearch(T& A, T e, Rank lo, Rank hi) {
	while (lo < hi) {
		Rank mi = (hi + lo) >> 1;
		e < A[lo] ? hi = mi : lo = mi + 1;//最后一项必是 lo = mi + 1;
	}
	return --lo;//严格按照语义执行
}
template <class T> Rank fibSearch(T& A, T 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;
		//总结
		//如果是初始值加区间长度,一定要减一
		//如果是[lo,hi)区间,区间长度 = hi - lo
		//for循环中i = 0(左闭)i<_size(右开),会循环[0,_size),区间长度 = _size,循环这么多次。
		//while循环中lo<hi ==> 0<hi - lo即循环到hi = lo终止//while循环中1< hi - lo即循环到[lo,hi),hi = lo+1
		//因此while循环左边是几(0,1,2……),区间长度就是几
		//但是指针不同,_elem+lo,就是指向lo这个位置
		(e < A[mi]) ? hi = mi : lo = mi + 1;
	}
	return --lo;
}

template<class T> Rank Vector<T>::search(T const& e, Rank lo, Rank hi) const {//有序向量区间查找
	//严格语义:有序向量查找,返回不大于e的最后一个元素
	return (rand() % 2) ? binSearch(_elem, e, lo, hi) : fibSearch(_elem, e, lo, hi);//0或1,各50%的规律。
}
template<class 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;}
template<class T> void Vector<T>::bubbleSort(Rank lo, Rank hi) {
	while (!bubble(lo, hi--));//一定是hi--,因为后面都是有序的
	//也就是每一趟的排序区间为[lo,hi--)
}
template<class T> Rank Vector<T>::max(Rank lo, Rank hi) {
	Rank i = 0, j = 0;
	while (++j < hi)
		if (_elem[i] < _elem[j]) i = j;
	return i;
}
template<class T> void Vector<T>::selectionSort(Rank lo, Rank hi) {
	while (lo<hi){
		Rank m= max(lo, hi);
		insert(--hi, _elem[m]);}
}
//*****非常完美的合并算法*****
template<class T> void Vector<T>::merge(Rank lo, Rank mi, Rank hi) {
	T* A = _elem + lo;//A = _elem[lo,hi]
	int lb = mi - lo; T* B = new T[lb];
	for (Rank i = 0; i < lb; B[i] = A[i++]);//B = _elem[lo, mi]
	int lc = hi - mi; T* C = _elem + mi;//C = _elem[mi, hi]
	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;
}
template<class T> void Vector<T>::mergeSort(Rank lo, Rank hi) {
	if (hi - lo < 2) return;
	Rank mi = (hi + lo) >> 1;//以终点为例
	mergeSort(lo, mi); mergeSort(mi,hi);
	merge(lo, mi, hi);
}

template<class 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;//快速排序
	}//快速排序
}

void main() {
	int A[5] = { 1, 2, 30, 45, 6 };
	Vector<int> test(A,0,5);
	test.sort(0,5);
	Rank a = test.find(5);
	cout << "**************************\n";
	cout << "\n";
	cout << "坚持,很强,又一次成功运行\n";
	cout << "\n";
	cout << "**************************\n";
	cout << "A+lo:"<<A+1 << "\n";
	for (int i = 0; i <5; cout << "i:" << i << "  A[i++]:" << A[i++]<< "  rand()" << rand()<<"  rand() % i:"  <<rand() % i << "\n");
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值