蓝桥备赛(四)- 数组(上)

发布于:2025-02-26 ⋅ 阅读:(15) ⋅ 点赞:(0)

数组是一组相同类型元素的集合

1. 数组中存放的是一个或者多个数据,但是数组元素个数不能为0

2. 数组中存放的多个数据类型是相同的。

一、一维数组

一维数组是最常见的 , 通常用来存放一组数据 , 一维数组是一块连续的空间 。

1.1 数组创建

一维数组创建的基本语法如下:

type arr_name [常量值];

可以使用 const int N = 100 的方式定义常量 , 然后使用N来指定数组的大小 --> int arr[N]

比如:我们现在想存储某个班级的20人的数学成绩,那我们就可以创建⼀个数组,如下:
int math[20];

//或者
const int N = 20;
int math[N]; 

我们也可以创建其他类型和大小的数组:

但是需要注意,数组的名字需要取得有意义先 , 方便我们记住。

char ch[8];
float f[10];

1.2 数组的初始化

数组初始化 : 数组创建的时候 , 给定一些初始值

--->  数据放在大括号中

1 .              int ar3[3] = { 1,2,3,4}        ---> 错误初始化,初始化项太多

2 .              int arr[] --->  如果没有指定大小和初始化,编译不过去

3 .              int arr[] = {1,2,3,4,5}         --> 编译成功,如果有初始化,可以不用写大小,编译器会自动根据初始化的项数来决定大小。

1.3 数组元素的访问

数组是有下标的 , 下标是从 0 开始的 , 假设数组有 n 个元素 , 最后一个元素的下标是 n-1 , 下标就相当于元素的编号 , 如下: 

 数组的访问提供了一个操作符 [ ] , 这个操作符叫:下标引用操作符

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int main()
{
	int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	cout << arr[3] << endl; // 4
	cout << arr[8] << endl; // 9
	return 0;
}

有了下标访问操作符 , 我们就可以访问到数组的元素了 。 同时我们也可以修改对应数组的数据;

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;

int main()
{
	int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
	cout << arr[3] << endl; // 4
	cout << arr[8] << endl; // 9
	arr[3] = 100;
	cout << arr[3] << endl; 
	return 0;
}

如果想要具体观察调试的过程 , 需要使用的VS;

1.4 数组和sizeof

1 . sizeof (数组名) , 计算的是数组的总大小 , 单位是字节

2 . sizeof(数组名)/ sizeof(第一个元素) , 计算的是数组的元素个数。

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	cout << sizeof(arr) << endl;
	cout << sizeof(arr) / sizeof(arr[0]) << endl;
	return 0;
}

1.5 数组元素的打印

如果想打印所有元素 , 就需要产生所有元素的下标即可 --> 可以使用for循环

注意 : 如果产生的下标超出了有效下标的范围 , 比如 : 使用负数作为下标 , 或者超出了下标的最大值 , 再使用这个下标访问元素就会造成 ---> 越界访问 。 越界访问访问的时候 , 代码编译时语法虽然每报错 , 但是运行时一定会出现问题

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (int i = 0; i < 10; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	return 0;
}

 优化 : 如果不知道数组的大小 , 但是需要打印全部数组元素 , 可以借助sizeof

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int s = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < s; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	return 0;
}

还可以输入数组元素 , 然后再打印 :

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	int arr[10] = { 0 };
	int s = sizeof(arr) / sizeof(arr[0]);
	for (int i = 0; i < s; i++)
	{
		cin >> arr[i];
	}
	for (int i = 0; i < s; i++)
	{
		cout << arr[i] << " ";
	}
	cout << endl;
	return 0;
}

 

1.6 范围for语法

在VS中 , 是支持C++11 , 但是在Dev-C++中 , 默认不支持C++11

Dev-C++不支持C++11怎么办 ?-CSDN博客

for (类型  变量名 : 数组名)

          语法  //多条语句需要加大括号

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (int e : arr)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

1. 上面代码中的for 就是范围 for :

意思就是  将arr 数组中的元素 , 依次放在e 变量中 ,然后打印e , 直到遍历完整个数组的元素 。

2 . 这里的e 是一个单独的变量 , 不是数组的元素 , 所以对 e 的修改 , 不会影响数组

3 . 慎重使用范围 for , for 是对所有的元素进行遍历的 , 但是我们在实际写题的时候 , 并不需要打印所有元素 , 这时就不能使用范围 for 了

#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (int e : arr)
	{
		e = -1;
	}
		for (int e : arr)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

 

1.7 auto关键字

auto 的主要用途是让编译器自动推导变量的类型 , 比如:

#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	auto a = 3.14;
	auto b = 100;
	auto c = 'x';
	
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
	return 0;
}

VS编译器更强大一些 , 鼠标放在变量面前 , 会显示出编译器自动推导出的类型:

所以我们可以修改一下上面的代码 :  

#include <iostream>
#include <cstdio>
using namespace std;

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (auto e : arr)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

 

1.7 memset 设置数组内容

memset - C++ Reference

memset

函数原型如下:

void * memset ( void * ptr, int value, size_t num );

memset 是用来设置内存的 , 将内存中的值以字节为单位设置想要的内容 , 需要头文件 <cstring>

设置数组内容

不要忘记包含头文件 <cstring>

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int main()
{
	char str[] = "Hello World!";
	cout << str << endl;
	memset(str,'x',6);
	cout << str << endl;
	
	cout << endl;
	
	//如果想要在第二个字符后面开始
	char str2[] = "Hello World!";
	cout << str2 << endl;
	memset(str2+2,'x',6);
	cout << str2 << endl;
	return 0;
}

注意 : int 类型的数组不能直接通过 cout << arr << end 来打印 , 需要遍历数组 ! 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;


int main()
{
	int arr[] = {1,2,3,4,5};
	for(auto e:arr)
	{
		cout << e << " ";
	}
	cout << endl;
	memset(arr,0,20);//4*5=20
	for(auto e:arr)
	{
		cout << e << " ";
	}
	cout << endl;
	
	cout << endl;
	
	//数组的大小也可以使用sizeof计算 
	int arr2[] = {1,2,3,4,5};
	for(auto e:arr2)
	{
		cout << e << " ";
	}
	cout << endl;
	memset(arr2,0,sizeof(arr2));
	for(auto e:arr2)
	{
		cout << e << " ";
	}
	return 0;
}

 

错误使用

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int main()
{
	int arr[] = {1,2,3,4,5};
	memset(arr,1,20);
	for(auto e:arr)
	{
		cout << e << " ";
	}
	cout << endl;
	
	return 0;
}

为啥不是1 ? 为啥不是1 ? 为啥不是1 ? 

因为 memset 是以字节为单位设置的 !

因为 memset 是以字节为单位设置的 !

因为 memset 是以字节为单位设置的 !

所以当value设置为 1 或者其他非0数字时候 , 打印结果不符合预期 。

原因:memset 函数是给每个字节设置value 值 , 而一个整型元素占用 4 个字节 , 一个整型的每个字节都设置为1 , 二进制就是 : 00000001000000010000000100000001 , 转化为十进制就是16843009 ; 

1.8 memcpy拷贝数组内容

memcpy - C++ Reference

在使用数组的时候 , 有时候我们需要将数组 a 的内容给数组b , 比如 :

int a[10] = { 1,2,3,4,5,6,7,8,9,10};

int b[0] = { 0 };

 如何做 ? 直接赋值 ?

b = a ;

不行 !!!

1 . 语法上 : 数组名是地址 , 地址是一个常量 , 常量是不可以被修改的 ( 类似3 = 5 )

2 . 逻辑上 :是需要拷贝数组的内容 , 而不是数组的地址 。

其实C++中有一个库函数 memcpy(memory copy) 可以做数组内容的拷贝 ,memcpy是用来做内存块的拷贝的 。 需要包含<cstring>头文件。

原型如下: 

void * memcpy ( void * destination, const void * source, size_t num );

 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int main()
{
	int a[10] = {1,2,3,4,5,6,7,8,9,10};
	int b[10] = {0};
	memcpy(b,a,10*sizeof(int));
	for(auto e:b)
	{
		cout << e << " ";
	}
	cout << endl;
	return 0;
}

 

1.9 练习

练习一:查找特定的值

B2093 查找特定的值 - 洛谷

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 10010;
int arr[N];

int main()
{
	int n;
	int x;
	cin >> n;
	for(int i = 0;i< n ; i++)
	{
		cin >> arr[i];
	}
	cin >> x;
	int i;
	for(i = 0;i < n ;i++)
	{
		if(arr[i] == x)
		{
			cout << i << endl;
			break;
		}
	}
	if(i == n)
	 cout << -1 << endl;
	return 0;
}

1 . 有的题目要求数据从下标 0 的位置开始存放 , 但有些题目是从 下标为1的位置存放 , 所以需要仔细阅读题目 , 避免越界 。

2 . 数组开辟空间需要足够 , 避免越界 。 一般题目需要 n 个空间 , 建议开辟 n + 10 个空间 ,这样空间十分充足 , 比较保险 。

3 . 一般数组比较大的时候 , 建议将数组创建成全局数组 , 因为局部的数组太大的时候 , 会导致程序无法正确运行 。全局遍历是在内存的静态区开辟空间 , 但是局部遍历是在栈区开辟空间的 , 每个程序的栈区空间是you'xian

练习二:数组逆序重存放

B2089 数组逆序重存放 - 洛谷

#include <iostream>
#include <cstdio>
using namespace std;

int arr[110];
int main()
{
	int n;
	cin >> n;
	for(int i = 0;i< n;i++)
	{
		cin >> arr[i];
	}
	for(int i = n - 1;i>=0 ; i--)
	{
		cout << arr[i] << " ";
	}
	return 0;
}

练习三:向量点积计算

B2091 向量点积计算 - 洛谷

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 1010;
int a[N];
int b[N];
int main()
{
	int n;
	cin >> n;
	for(int i = 1 ;i <= n ; i++)
	{
		cin >> a[i];	
	}	
	for(int i = 1 ;i <= n ; i++)
	{
		cin >> b[i];	
	}
	//计算
	int sum = 0;
	for(int i = 1 ;i <= n ; i++)
	{
		sum += a[i]*b[i];
	}
	cout << sum << endl;
	return 0;
}

 a数组的内容读完后 , 才读取 b 的数据 , 我们可以边读取 b 的数据 , 边计算和 , 数组b的数据不需要特地的存储 。

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 1010;
int a[N];
int main()
{
	int n;
	cin >> n;
	for(int i = 1 ;i <= n ; i++)
	{
		cin >> a[i];	
	}	
	//计算
	int sum = 0;
	int b = 0;
	for(int i = 1 ;i <= n ; i++)
	{
		cin >> b;
		sum += a[i]*b;
	}
	cout << sum << endl;
	return 0;
}

B2091 向量点积计算 - 洛谷

练习四:年龄与疾病

B2090 年龄与疾病 - 洛谷

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 110;
int arr[N];
int n1,n2,n3,n4;
int main()
{
	int n;
	cin >> n;
	for(int i = 0;i < n;i++)
	{
		cin >> arr[i];
	}
	//统计
	for(int i = 0;i < n;i++)
	{
		if(arr[i] >= 0 && arr[i] <= 18)
			n1++;
		else if(arr[i] >= 19 && arr[i] <= 35)
			n2++;
		else if(arr[i] >= 36 && arr[i] <= 60)
			n3++;	
		else
			n4++;
	}
	printf("%.2f%%\n",n1 * 1.0 / n *100);
	printf("%.2f%%\n",n2 * 1.0 / n *100);
	printf("%.2f%%\n",n3 * 1.0 / n *100);
	printf("%.2f%%\n",n4 * 1.0 / n *100);
	return 0;
}

优化 : 我们不需要特意的创建一个数组来存储病人的年龄 , 可以在每输入一个病人的年龄的时候 就立即统计 新输入病人年龄所归属的 年龄段即可 。

#include <iostream>
#include <cstdio>
using namespace std;

int n1,n2,n3,n4;
int main()
{
	int n;
	cin >> n;
	int age;
	//统计
	for(int i = 0;i < n;i++)
	{
		cin >> age;
		if(age >= 0 && age <= 18)
			n1++;
		else if(age >= 19 && age <= 35)
			n2++;
		else if(age >= 36 && age <= 60)
			n3++;	
		else
			n4++;
	}
	printf("%.2f%%\n",n1 * 1.0 / n *100);
	printf("%.2f%%\n",n2 * 1.0 / n *100);
	printf("%.2f%%\n",n3 * 1.0 / n *100);
	printf("%.2f%%\n",n4 * 1.0 / n *100);
	return 0;
}

练习五:开关灯

B2092 开关灯 - 洛谷

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 5010;
int arr[N] = {0};
//1 -- 开
//0 -- 关 
int main()
{
	int n;
	cin >> n;
	//i 是人的编号 
	for(int i = 2;i <= n ; i++)
	{
		int j = 0;
		//j是灯的编号 
		for(j = i ; j <= n ; j++)
		{
			if(j%i == 0)
			{
				if(arr[j] == 0)
					arr[j] = 1;
				else
					arr[j] = 0; 
			}
		}
	}
	//输出
	for(int i = 1;i <=n ; i++)
	{
		if(arr[i] == 0)
			cout << i << " ";
	 } 
	return 0;
}

如下 , 还可以对代码进行优化 : 

 

练习六:小鱼比可爱

P1428 小鱼比可爱 - 洛谷

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 110;
int arr[N];
int main()
{
	int n;
	cin >> n;
	for(int i = 0;i < n ; i++)
	{
		cin >> arr[i];
	}
	// i 表示鱼的编号 
	for(int i = 0; i < n ; i++)
	{
		int c = 0;
		// j 表示第 i 条鱼前面的鱼的编号 
		for(int j = 0;j < i ; j++)
		{
			if(arr[j] < arr[i])
			{
				c++;
			}
		}
		cout << c << " ";
	}
	return 0;
}

练习七:冒泡排序

信息学奥赛一本通(C++版)在线评测系统

#include <iostream>
#include <cstdio>
using namespace std;

const int N = 30;
int arr[N];
int main()
{
	int n;
	cin >> n;
	int i = 0;
	//输入数据 
	for(int i = 0; i < n ; i++)
	{
		cin >> arr[i];
	}
	//排序 
	//i 表示趟数 
	for(i = 0;i < n - 1 ; i++)
	{
		//j 表示比较次数 
		for(int j = 0 ; j <= n - i - 1 ; j++)
		{
			if(arr[j] < arr[j+1])
			{
				int tmp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = tmp;
			}
		}
	}
	
	//打印
	for(int i = 0 ; i < n ; i++)
	{
		cout << arr[i] << endl;	
	} 
	return 0;
}