当前位置: 首页 > article >正文

传统数组 vs vector和list

传统的数组:

int arr[10]; 传统的数组有以下的缺点:

1)长度不可修改

2)内存分配

局部数组:把数组定在函数内, 数组便是局部变量,故会被分配在栈上 但栈的大小是有限制的 ,故其在内存中不能超过1MB。 如果数组太大,可能会导致栈溢出。

int arr[1000000];  // 如果超出了内存限制,可能会失败

全局数组: 如果将数组声明为全局变量,数组会分配在数据段或 BSS 段中,不会受到栈大小的限制。但是,OJ(在线评测系统)通常对内存有严格的限制。如果数组过大,可能会超出内存限制,导致超时或内存不足的错误。

3)数组作为参数不方便。

在c语言中,将数组作为参数,实际上是传递数组的首地址,即传递的是指针,而不是整个数组。

故被调用函数只能得到数组的首地址,而无法得到数组的长度。

在做oj时要求用纯c解题,怎么解决上面的问题:

==》

1)一开始申请一个大的数组,如果局部数组的长度无法满足要求,就将数组定义为全局数组。若全局数组的占用内存超过了题目的内存限制。就是算法有问题。

我们也可以使用动态内存分配(malloc/realloc)来模拟动态数组,并手动管理内存。

2)在传参的时候传两个参数,数组的地址 和长度。

// 分配初始内存
int* arr = (int*)malloc(sizeof(int) * initial_size); //动态扩展数组
arr = (int*)realloc(arr, sizeof(int) * new_size); 
//传递数组的指针和长度
void func(int* arr, int size) {
   
}
 

但若用c/c++,更好用的办法就是使用c++提供的vector,即动态数组。

vector的使用

都说:" 传统的静态数组 的大小在编译时就已经固定,无法在程序运行时修改。 而动态数组可以",对于这句话,通俗一点讲,就是说:

我们可以在写代码时不必定义其大小,即使定义了,我们也可以在后续的代码中使用各种方法插入或删除其元素,因为其在运行时会根据我们的代码操作自动调整其内存的 。

vector是c++提供的STL。他有一些优点;

1) 会自动处理内存分配和释放 , 免了 C 语言中常见的内存管理错误。

2) 通过 vector::size() 可以轻松获取数组的长度。

3)提供了丰富的成员函数

我们主要学习vector的增删查改。

引入

#include<vector>

增:

增操作包括初始化和插入;

1.初始化
vector<int> vec;
vector<double> vec;

注:vector不是类型,vector< type>才是类型,故下面的vec1和vec2不是同一种类型。

当然了也可以自定义一个类,从而可以定义vector<MyType>类型的变量;

struct MyType{
int val1;
double val2;
}
vector<MyType>vec;

另外,vector<int>也可以作为一种类型放在vector的<>中,

构成vector<vector<int>>,这种类型便是代表动态数组的动态数组,即二维数组。

vector<vector<int>>

在机试中,对于二维数组,推荐使用动态数组的静态数组,即下面这种写法;以应用于实现图算法中的邻接表。

vector<int> arr[10];
2.插入

插入数据使用push_back: 往动态数组的尾部插入;

我们知道,往顺序表中插入元素代价很大,而这种往数组末尾插入元素的操作非常高效,但若如果我们硬要往任意位置插入元素,该怎么办?

==》可以使用迭代器,我们稍后解答

int a;
while(scanf("%d",%a)!=EOF){
    vec.pushback(a);//往vec尾部插入a
}

查找

1、根据数组下标访问对应元素
//定义的这个数组下标从0到4
vector<int> vec={1,23,4};
int i=0;
printf(“vec[i]=%d\n",vec[i]);
2.遍历整个vector(for,迭代器)

vector本身携带了长度的信息,可以使用vec.size()获取长度

从而可以使用for循环遍历数组

int size=vec.size();
for(int i=0;i<size;i++){
​
}

除了用普通for循环,还可以使用迭代器

其提供了一种通用方法;可以访问不同类型的数据结构;我们可以将迭代器理解为一个高级的指针;

迭代器的类型是:动态数组类型::iterator

例vecotor<int>::iterator

对于一个数组,{1,3,5,7,9}

我们可以使用begin()来获取第一个元素的位置;使用end()来获取尾后的位置;当我们对迭代器做自增操作,他便会后移;他的用法如下:

vector<int> vec={1,3,5,7,9};
vector<int>:: iterator it;
for(it=vec.begin();it!=vec.end();it++){
printf("it=%\n",*it);
}

现在解决上面硬要往任意位置插入元素的问题:

因为迭代器可以访问到数组中任意一个位置;所以可以利用它对任意位置插入,删除元素。(insert和erase)

因为insert和erase会修改动态数组的结构,所以插入或修改完成后it的指向无意义。所以之后要对迭代器重新赋值。

但是这种插入操作最好避免使用;而使用push_back进行插入

vector<int>:: iterator it;
it=vec.begin();
vec.insert(it,2); //往it所在位置插入元素2
//注意迭代器要重新赋值
it=it+3;//it+3相当于3次++,只能在vector中使用
3.通过元素信息查找其位置

1.删除一个元素

我们可以使用pop_back()删除最后一个位置的元素。

vec.pop_back();

同样的,如果我们硬要删除一个位置的元素,可以使用迭代器配合erase函数。

vecor.erase(it);
2.把vector清空
vector.clear()

list的使用

前面我们讲过,即使使用迭代器配合insert和erase函数能够在任意位置对数组进行增加和删除操作,但是还是不推荐那样做。因为,如前面所言,顺序表的线性结构进行这样的操作真的很低效。所以,如果我们硬要做,就不能使用传统的线性结构,而得使用链式结构。

c++标准库为我们提供了一个链式结构的顺序表,叫list。

list的底层原理是一个双向链表。

引入

#include<list>

增 insert

前面我们在vector中对于迭代器,使用了it+=3表示迭代器it++了3次,但是因为链表中不支持随机访问,故不支持加法运算符,故只能靠自增3次来实现;

list<int> ls={1,3,4,5,6};
//获取迭代器
list<int>::iterator it=ls.begin();
it++;
it++;
it++;
ls.insert(it, 10);

it.erase();

遍历list

for(it=ls.begin();it!=ls.end();it++){
printf("it=%d\n",*it);
}

vector和list的选择

若一个题目中要求使用一个线性的数据结构,我们首选vector,

但如果你发现这个vector在使用的过程中存在着大量的对中间元素进插入和删除的操作,就改用list。

补充解惑:

1.为什么往线性表中的任意元素插入或删除元素很低效?

====》

线性表(如 vector)的底层是一个连续的内存块(数组)。在往数组中间插入或删除元素时,需要移动其他的元素。

因此 插入和删除最坏情况下的事件复杂度都是为o(n)。

2.list的增删改查都是使用迭代器完成的吗?

===>

是的,list 的增删改查主要是通过迭代器来完成的。

由于 list 是基于链表实现的, 因此没有下标访问的方式,只能通过迭代器进行增删改查。 迭代器提供了一个统一的接口来遍历、修改 list 中的元素,增加了代码的灵活性和可移植性。

ls.insert(it, 10);

ls.erase(it);

std::cout << *it << " ";


http://www.kler.cn/a/548987.html

相关文章:

  • rust学习笔记1-window安装开发环境
  • 总部年会天府感怀
  • 数据结构 红黑树和set/map
  • docker部署笔记软件memos,通过5320端口访问,如何通过nginx反向代理配置访问?
  • Cherno C++ P55 宏
  • 力扣 最长递增子序列
  • 容器、pod和缓存
  • 第三十三周学习周报
  • 数据结构:图;邻接矩阵和邻接表
  • 进程等待与进程替换
  • 基于Spring Boot的宠物爱心组织管理系统的设计与实现(LW+源码+讲解)
  • 计算机视觉+Numpy和OpenCV入门
  • C++:构造函数,static成员,友元,内部类
  • ASUS/华硕 全系列原厂系统 家庭版 专业版系统 工厂文件 带ASUS Recovery恢复
  • selenium webdriver/chrome driver集合整理130/131/132/133/134/135
  • ELK架构基础
  • (前端基础)HTML(二)
  • 2025-02-13 学习记录--C/C++-PTA 7-16 求符合给定条件的整数集
  • 1.从零开始学会Vue--{{基础指令}}
  • DOS网络安全