L2-数据结构基础-第07课-动态数组

L2-数据结构基础-第07课-动态数组

原创 葫芦老师 云帆优培 2020-12-19 13:34
L2-数据结构基础-第07课-动态数组
变长数组

cin >> n;
int a[n];

上面的代码, 严格说来, c++ 标准上是不支持的, 尽管大部分编译器能编译过.

c++ 是 c 的超集, 但是却不支持变长数组, 是因为c++ 提供了更强大的动态数组 vector.

在信息学竞赛中,有些题目需要定义很大的数组,这样会出现“超出内存限制"的错误。比如,如果一个图的顶点太多,使用邻接矩阵就会超出内存限制,使用指针实现邻接表又很容易出错,而使用vector实现简洁方便,还可以节省存储空间。

vector

vector是动态数组, 可以容纳许多类型的数据,因此也被称为容器

vector头文件

#include <vector>

vector初始化

template <class T>

这里的尖括号, 不是大于号, 小于号, 这里面放的是 「类型形式参数」 . 这个尖括号要特别注意加空格, 否则可能会变成 >> 或者 << .

比如:

vector <vector<int> > mp  // 两个 > > 之间必须有空格.
vector <int> a; //生成一个名为a,保存int型对象的vector
vector <string> b; //生成一个名为b,保存string对象的vector
vector <vector<int> > mp; //生成一个保存vector型变量的vector

方式1 给定大小

vector<int> a(10);
//定义具有10个整型元素的向量(尖括号为元素类型名,它可以是任何合法的数据类型),不具有初值,其值不确定

方式2 给定大小和初始值

vector<int> a(10, 1);
//定义具有10个整型元素的向量,且给出的每个元素初值为1

方式3 用向量/数组初始化

vector<int> a(b);
//用向量b给向量a赋值,a的值完全等价于b的值

vector<int> a(b.begin(), b.begin+3);
//将向量b中从0-2(共三个)的元素赋值给a,a的类型为int型

int b[7]={1,2,3,4,5,6,7};
vector<int> a(b, b+7;
 //从数组中获得初值

关于数组和向量的不同和相似之处如下表所示

在这里插入图片描述

vector是动态数组,在堆中分配内存

vector与数组一样,都是分配的一段连续的内存空间,并且起始地址不变,因此能够很好支持随机存取,复杂度为 O(1) 。但是在头部或者中间进行插入和删除的时候会涉及元素的移动,即内存块的拷贝,所以在中间插入或者删除元素的复杂度为 O(n)对最后元素操作最快(在后面添加删除元素最快),此时一般不需要移动内存。

vector对象的几个重要操作

#include<vector>
vector<int> a, b;

//b为向量,将b的0-2个元素赋值给向量a
a.assign(b.begin(), b.begin() + 3);

//a含有4个值为2的元素
a.assign(4, 2);

//返回a的最后一个元素
a.back();

//返回a的第一个元素
a.front();

//返回a的第i元素,当且仅当a存在
a[i];

//清空a中的元素
a.clear();

//判断a是否为空,空则返回true,非空则返回false
a.empty();

//删除a向量的最后一个元素
a.pop_back();

//删除a中第一个(从第0个算起)到第二个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)结束
a.erase(a.begin()+1, a.begin()+3);

//在a的最后一个向量后插入一个元素,其值为5
a.push_back(5);

//在a的第一个元素(从第0个算起)位置插入数值5,
a.insert(a.begin()+1, 5);

//在a的第一个元素(从第0个算起)位置插入3个数,其值都为5
a.insert(a.begin()+1, 3, 5);

//b为数组,在a的第一个元素(从第0个元素算起)的位置插入b的第三个元素到第5个元素(不包括b+6)
a.insert(a.begin()+1, b+3, b+6);

//返回a中元素的个数
a.size();

//返回a在内存中总共可以容纳的元素个数
a.capacity();

//将a的现有元素个数调整至10个,多则删,少则补,其值随机
a.resize(10);

//将a的现有元素个数调整至10个,多则删,少则补,其值为2
a.resize(10, 2);

//将a的容量扩充至100,
a.reserve(100);

//b为向量,将a中的元素和b中的元素整体交换
a.swap(b);

//b为向量,向量的比较操作还有 != >= > <= <
a==b;

顺序访问vector的几种方式

向向量a中添加元素

vector<int> a;
for(int i = 0; i < 10; i++) {
    a.push_back(i);
}

通过下标方式获取

int a[6]={1,2,3,4,5,6};
vector<int> b(a,a+4);

for(int i = 0; i <= b.size() - 1; i++) {
    cout << b[i] << endl;
}

通过迭代器方式读取

int a[6] = {1, 2, 3, 4, 5, 6};
vector<int> b(a, a+4);
vector<int>::iterator it;
for( it = b.begin(); it != b.end(); it++) {
    cout<< *it << "  ";
}

几种重要的算法

#include <algorithm>

//对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
sort(a.begin(), a.end());

//对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
reverse(a.begin(), a.end());

//把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
copy(a.begin(), a.end(), b.begin()+1);

//在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
find(a.begin(), a.end(), 10);

初始化二维vector

// 初始化一个 二维的matrix, 行M,列N,且值为0
vector<vector<int> > matrix(M, vector<int>(N));

//等价于下面的
vector<vector<int> > matrix(M);
for(int i=0;i<M;i++) {
    matrix[i].resize(N);
}

//等价于下面的
vector< vector<int> > matrix;

matrix.resize(M);//M行
for(int i=0;i<matrix.size();i++){
    matrix[i].resize(N);//每一行都是N列
}

// 初始化一个 二维的matrix, 行M,列N,且值自定义为data;
vector<vector<int>> matrix(M, vector<int>(N,data));

学会用大括号初始化二维数组

vector<vector<int>> matrix1{};
vector<vector<int>> matrix2{ {1}, {1, 1} };//学会用大括号初始化二维数组
matrix1.push_back({ 1, 2, 1 });//插入

初始化一个 二维vector,行M,列不固定

vector<vector> matrix(M); //M行,列数不固定
int col;
vector<int> temp;
for(int i = 0; i < M; i++){
    cout << "please input the col of "<<i<<" row" << endl;
    cin >> col;//确定第i行的列数
    cout << i << " row has "<< col << " col " << " please input these " << endl;
    for(int j = 0; j < col; j++{
        int data;
        cin >> data;
        temp.push_back(data);
    }

    matrix[i] = temp;

    temp.clear();
}

初始化一个二维vector, 行列都不固定

#include <iostream>
#include<vector>
using namespace std;
int main()
{
    vector<vector<int>> matrix;//行,列数不固定
    cout << "please input rows of matrix: " << endl;
    int rows;
    cin >> rows;
    matrix.resize(rows);
    int col;
    vector<int> temp;
    for (int i = 0; i < rows; i++) {
        cout << "please input the cols of " << i << "th row" << endl;
        cin >> col;//确定第i行的列数
        cout << i << "th row has " << col << " cols," << "please input these" << endl;
        for (int j = 0; j < col; j++){
            int data;
            cin >> data;
            temp.push_back(data);
        }
        matrix[i] = temp;
        temp.clear();
    }

    cout << "output matrix:" << endl;
    for (int i = 0; i < matrix.size(); i++) {
        for (int j = 0; j < matrix[i].size(); j++) {
            cout << matrix[i][j] << " ";
        }
        cout << endl;
    }
    cout << endl;
    return 0;
}

例题 寄包柜

P3613 【深基15.例2】寄包柜

题目描述
超市里有 个寄包柜。每个寄包柜格子数量不一,第 i 个寄包柜有 个格子,不过我们并不知道各个 的值。对于每个寄包柜,格子编号从 1 开始,一直到 。现在有 次操作:

1 i j k:在第 i 个柜子的第 j 个格子存入物品 。当 k=0 时说明清空该格子。

2 i j:查询第 i 个柜子的第 j 个格子中的物品是什么,保证查询的柜子有存过东西。

已知超市里共计不会超过 个寄包格子, 是确定然而未知的,但是保证一定不小于该柜子存物品请求的格子编号的最大值。当然也有可能某些寄包柜中一个格子都没有。

输入格式
第一行 2 个整数 n 和 q,寄包柜个数和询问次数。

接下来 q 个整数,表示一次操作。

输出格式
对于查询操作时,输出答案。

输入输出样例
输入

5 4
1 3 10000 114514
1 1 1 1
2 3 10000
2 1 1

输出

114514
1

分析
内存限制 125M, 可以存放int类型的个数是 125 * 1024 * 1024 / 4 = 32768000. 所以 个格子是能存下的.

但是 但是, 寄包柜有 个, 每个寄包柜有 格子. 如果定义一个二维数组, 就会需要 个 int 所以 MLE.

那就用vector吧.

我们仍然不知道, 每个柜子有多少格子, 所以需要记录两个量, 一个是格子编号, 一个是格子里的物品. 先找编号, 然后找到该编号下的物品.

参考答案

#include <iostream>
#include <vector>

using namespace std;

const int N = 100005;

vector <int> a[N];
vector <int> idx[N];

int n, q;

int main()
{
 cin >> n >> q;
 while(q--) {
  int opt, i, j, k;
  cin>>opt;
  if(opt == 1) {
   cin >> i >> j >> k;
   idx[i].push_back(j);
   a[i].push_back(k);
  }
  else {
   cin >> i >> j;
   for(int id = a[i].size() - 1; i >= 0; id--) {
    if(idx[i][id] == j) {
     cout<<a[i][id]<<endl;
     break;
    }
   }
  }
 }
 return 0;
}

例题 杂务

P1113 杂务

题目描述
John的农场在给奶牛挤奶前有很多杂务要完成,每一项杂务都需要一定的时间来完成它。比如:他们要将奶牛集合起来,将他们赶进牛棚,为奶牛清洗乳房以及一些其它工作。尽早将所有杂务完成是必要的,因为这样才有更多时间挤出更多的牛奶。当然,有些杂务必须在另一些杂务完成的情况下才能进行。比如:只有将奶牛赶进牛棚才能开始为它清洗乳房,还有在未给奶牛清洗乳房之前不能挤奶。我们把这些工作称为完成本项工作的准备工作。至少有一项杂务不要求有准备工作,这个可以最早着手完成的工作,标记为杂务1。John有需要完成的n个杂务的清单,并且这份清单是有一定顺序的,杂务k(k>1)的准备工作只可能在杂务1至k−1中。

写一个程序从1到n读入每个杂务的工作说明。计算出所有杂务都被完成的最短时间。当然互相没有关系的杂务可以同时工作,并且,你可以假定John的农场有足够多的工人来同时完成任意多项任务。

输入格式
第1行:一个整数n,必须完成的杂务的数目(3≤n≤10,000);

第2至(n+1)行:共有n行,每行有一些用1个空格隔开的整数,分别表示:

工作序号(1至n,在输入文件中是有序的);

完成工作所需要的时间len(1≤len≤100);

一些必须完成的准备工作,总数不超过100个,由一个数字0结束。有些杂务没有需要准备的工作只描述一个单独的0,整个输入文件中不会出现多余的空格。

输出格式
一个整数,表示完成所有杂务所需的最短时间。

输入输出样例
输入 #1复制

7
1 5 0
2 2 1 0
3 3 2 0
4 6 1 0
5 1 2 4 0
6 8 2 4 0
7 4 3 5 6 0

输出 #1复制

23

分析
这道题稍微复杂点. 建模的话, 每个任务有若干个前提任务, 这些任务都完成后, 该任务才能完成. 我们可以用vector

参考代码

#include <bits/stdc++.h>
using namespace std;

int n;
struct task {
  int len;
  vector<int> kl;
};
task k[10001];
int maxlen, len;

int main()
{
 int i, p;

 scanf("%d", &n);
 for(i = 1; i <= n; i++) {
  scanf("%d %d", &p, &k[i].len);
  while(true) {
   scanf("%d",&p);
   if(p == 0)
    break;
   k[i].kl.push_back(p);
  }
 }

 for(i = 1; i <= n; i++) {
  len = 0;
  for(int j = 0; j < k[i].kl.size(); j++) {
   len = max(len, k[k[i].kl[j]].len);
  }
  k[i].len += len;
  maxlen = max(k[i].len, maxlen);
 }

 printf("%d", maxlen);
 return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值