数据结构之向量(1)
一、C++ 基础知识
1.四个内存空间
- 代码区
- 全局变量和静态变量区:储存的是常量和全局变量
- 局部变量区(栈区):储存的是局部变量
- 自由存储区(free store),也叫堆区
2.动态储存分配
虽然全局变量是在程序开始运行前在全局区分配的储存空间
而局部变量是在程序运行到该局部区域分配的储存空间
但编译器在编译时就知道这个变量所需内存空间的大小
这就是“静态储存分配”
但是,有时在编译时无法预定分配空间,只能根据运行时的要求进行内存分配,这就是“动态储存分配”
3.在堆区中,内存的分配与释放
//动态数组的建立与撤销
char*pc;
pc=new char[10];//new 运算符返回的是指针,我们是通过指针来操作我们所创建的对象的
// 动态创建的对象本身是没有名字的。但是静态定义变量或对象时,要用标识符命名,例如int a (a是标识符)
// int* p=new int(0) ; 在该语句里,new的作用:在自由存储区为对象或变量分配内存,并且用括号里的值来初始化
delete []pc;
//delete pc;会导致回收不彻底
上文围绕动态数组介绍了一些在C++里的基础知识,现在我们可以开始介绍向量。
4.从数组到向量
向量是数组的引用和泛化,向量本身就是由一组元素按线性次序封装而成。
向量有以下优点:
1.可以寻秩访问
2.元素的类型不局限于基本元素,可较为便捷的参与复制数据结构的定制与实现
下面是例子(可以自己跑一下,来体会一下):
std::vector<int> s(3,43);// 43 43 43
//优点:可较为便捷的参与复制数据结构的定制与实现
s.insert(s.begin()+ 1, 2022);//43 2022 43 43
s.erase(s.end() - 2, s.end());//43 2022
for (int i = 0; i < s.size(); i++)
std::cout << s[i] << std::endl; //优点:寻秩访问
4.1 vector容器的用法
vector的api参考文档
上面的链接有全部的api说明,下面介绍几点我认为要注意的地方
4.1.1
//初始化
std::vector<int> s(8); // 0 0 0 0 0 0 0 0
//函数原型是vector(n,elem),elem默认是0
//一般来说,我们直接std::vector<int> s就可以了
//但是有时必须要有参数,如下面链接中的题,该题的第一种解法就涉及vector,详细内容见题解
4.1.2
//赋值
std::vector<int> v1;//0 1 2 3 4 5 6 7 8 9
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
std::vector<int> v2;
v2.assign(v1.begin(), v1.end());//0 1 2 3 4 5 6 7 8 9
//上面的函数原型是:assign(begin,end)
//[begin,end)区间中的数据拷贝赋值给本身,这里要**注意左闭右开**
5.向量的实现
我们想要写出一个自己的向量模板类(myvector)
template<typename T>class myvector
{
private:
Rank _size;//using Rank=int
int capacity;
T* _elem;
public:
myvector(int c = DEFINE_CAPATITY, int s = 0, T v = 0);
里头会涉及许多操作,如插入、删除···,我们对其中一些算法进行详细的介绍。
5.1 扩容算法的实现
在扩容算法中,如果容量不够,我们采用的方法是将原容量乘2,为什么是乘2,而不是加一个定值呢?这就涉及到了均摊复杂度和均摊复杂度。
平均复杂度 | 均摊复杂度 |
---|---|
根据各种操作出现概率的分布,将对应的成本加权平均 | 连续实施的足够多次操作,所需总体成本摊还至单次操作 |
- 递增扩容
- 加倍扩容
还有一些操作,等下次接着写