数据结构之vector的实现
Vector类分为:构造函数、析构函数、只读函数、修改函数、私有函数、成员变量(数据区和大小)
# include <iostream>
# include <algorithm>
# include <cstdlib>
# define DEFAULT_CAPACITY 3
template <typename T> struct pp {
	void operator()(T & e) {
		std::cout << e << "\n";
	}
};
void bubbleSort(int * a, int n = 13)
{
	bool isSorted = false;
	for (int i = n - 1; !isSorted && i > 0; --i) // 待排序范围
	{
		isSorted = true;
		for (int j = 0; j < i; ++j) // 从开头到无序的前一个位置
		{
			if (a[j] > a[j + 1])
			{
				std::swap(a[j], a[j + 1]);
				isSorted = false;
			}
		}
	}
	return;
}
template <typename T> class Vector
{
public:
	// 析构函数
	~Vector() { delete []elem; }
	// 构造函数
	Vector(int c = DEFAULT_CAPACITY, int s = 0, T v=0)  // c 容量 s 规模 v 每个元素初始值
	{
		elem = new T[c];
		for (size = 0; size < s; ++size)
		{
			elem[size] = v;
		}
	}
	Vector(const Vector<T> & v) { copyForm(v.elem, 0, Vector.size); }
	Vector(T const * A, int lo, int hi) { copyForm(A, lo, hi); }
	// 运算符重载
	Vector<T>& operator = (const Vector<T> & v) // 
	{
		delete[]elem;
		elem = new T[v.capacity];
		copyFrom(v, 0, v.size);
		return *this;
	}
	T& operator[](int rank)
	{
		return elem[rank];
	}
	//  置乱
	void permute(void)
	{
		for (int i = size - 1; i > 0; --i)
		{
			std::swap(elem[i], elem[rand() % (i + 1)]);
		}
	}
	void unsort(int lo, int hi)
	{
		T * V = elem + lo;
		for (int i = hi - lo - 1; i > 0; --i)
		{
			std::swap(V[i], V[rand() % (i + 1)]);
		}
	}
	// 查找
	int find(T const & e, int lo, int hi)
	{
		for (; hi > lo && e != elem[hi - 1]; hi--);
		return hi;
	}
	// 插入
	void insert(T const & e, int rank)
	{
		expand();
		for (int i = size; i > rank; --i)
		{
			elem[i] = elem[i - 1];
		}
		elem[rank] = e;
		++size;
	}
	// 删除
	void remove(int lo, int hi)
	{
		if (lo == hi) return;
		for (int i = lo; i < size - hi + lo; ++i)
		{
			elem[i] = elem[i + hi - lo];
		}
		size -= hi - lo;
		shrink();
	}
	void remove(int rank)
	{
		remove(rank, rank + 1);
	}
	//  唯一化 返回删了多少个
	int unique(void)
	{
		int oldSize = size;
		for (int i = 0; i < size; ++i)
		{
			if (find(elem[i], i + 1, size)) remove(i);
			size--;
		}
		return oldSize - size;
	}
	// 遍历
	template <typename T2> void traverse(T2 & visit)
	{
		for (int i = 0; i < size; ++i)
		{
			visit(elem[i]);
		}
	}
	//*****************************************************以下是有序向量操作***************************************************
	// 有序性甄别,返回无序对儿数
	int disOrdered(void) const
	{
		int n = 0;
		for (int i = 0; i < size - 1; ++i)
		{
			if (elem[i] > elem[i + 1]) ++n;
		}
		return n;
	}
	// 针对有序vector的唯一化,O(n)
	void unique_ordered(void)
	{
		int i = 0, j = 1;
		while (j < size)
		{
			if (elem[i] == elem[j]) ++j;
			else
			{
				elem[i + 1] = elem[j];
				++i;
				++j;
			}
		}
		size = i + 1;
	}
	// 二分查找,找最靠右的等于e的元素的位置
	int search(const T & e)
	{
		int lo = 0; hi = size;
		while (lo < hi)
		{
			int mi = (lo + hi) / 2;
			if (e < mi) hi = mi;
			else lo = mi + 1;
		}
		return lo-1;
	}
protected:
	int size;
	int capacity;
	T * elem; //数据区
	void copyForm(T const * A, int lo, int hi) // 左开右闭,仅在构造时使用,所以从0开始装
	{
		elem = new T[(hi - lo) * 2];
		capacity = (hi - lo) * 2;
		size = 0;
		while (lo < hi)
		{
			elem[size] = A[lo];
			++size;
			++lo;
		}
	}
	void expand(void)
	{
		if (size < capacity) return;
		if (capacity < DEFAULT_CAPACITY) capacity = DEFAULT_CAPACITY;
		capacity *= 2;
		T * oldElem = elem;
		elem = new T[capacity];
		for (int i = 0; i < size; ++i)
		{
			elem[i] = oldElem[i];
		}
		delete[]oldElem;
		return;
	}
	void shrink(void)
	{
		if (capacity * 1.0 / size > 0.25) return;
		if (capacity < DEFAULT_CAPACITY * 2) capacity = DEFAULT_CAPACITY * 2;
		capacity /= 2;
		T * oldElem = elem;
		elem = new T[capacity];
		for (int i = 0; i < size; ++i)
		{
			elem[i] = oldElem[i];
		}
		delete[]oldElem;
		return;
	}
};
总结·易错篇:
- 该模板类的类型是Vector<T>而非Vector
- 模板template <typename T>和template <class T>的区别
- return * this
- 把elem数组封装为向量的好处:避免野指针,指针指向向量对象,里边包着的永远是有效的elem,若直接指向elem,则随着脱壳,指针无法及时的指向新壳。
- # define DEFAULT_CAPACITY 3;不能写分号
  
- 非常量引用只能绑定到左值 简言之,临时对象不能寻址。出现这个错误的原因就是进行了强制类型转换+函数引用调用。
总结·效率篇:
- const 类型名 & 变量名效率高
- 代码的重用,比如写operate=()时,可以用写好的copyFrom(),就不用重写详细的复制过程了
- expand()为什么不重用- copyFrom(),因为涉及到capacity的设置,在capacity很小的时候,是直接扩到最小容量,再二倍。
- 二分查找与Fibonacci查找


![[centos]安装mysql8.0.26](https://img-blog.csdnimg.cn/7fd8ee320a3f40e8b2c8a2b8b13b1e0f.png)
















