一维数组的了解

数组是一种基本的数据结构,用于存储一系列相同类型的元素。从这个定义我们可以看出数组的声明并不是声明一个个单独的变量,比如 student0、student1、…、student99(共100个变量),而是声明一个能保存这些相同类型的变量,比如 students。这个变量可以用students[0]、students[1]、…、students[99] 的形式来代表一个个单独的变量。

数组中的特定元素可以通过索引访问。数组是由连续的内存位置组成的,最低的地址对应第一个元素,最高的地址对应最后一个元素。比如students数组中的第一个元素是students[0],第二个元素是students[1]……,最后一个元素是students[99]。中括号内的数字就是某个元素的索引(index)。

1.数组的声明和初始化
在C++中,声明一个一维数组需要指定数组的类型、名称和大小。语法如下:
type arrayName[arraySize];
type 可以是任意有效的 C++ 数据类型,如int、float等;arrayName符合C++关于标识符定义的规则即可;arraySize 必须是一个大于等于零的整数常量(或变量)。例如,要声明一个类型为 int的包含 100个元素的数组 students,声明语句如下:
int students[100];
现在 students就 是一个可用的数组,可以容纳 100 个int 类型的数字。这里要特别注意,arraySize部分的值可以为0,也可以是变量(但是我们不建议这么做)。比如下面的定义都是合法(但不推荐)的:

int n = 100;
int array1[0];
int array2[n];

推荐的做法是结合宏定义来声明全局数组(在函数外定义的数组称为全局数组),如下所示:

#include<bits/stdc++.h>
using namespace std;
#define N 100
int students[N];

int	main() 
{
	
	return 0;
}

2.初始化数组
C++语言中,全局数组每个元素都会被自动初始化为数字0(无论任何类型)。而非全局数组(在函数内定义的数组)的每个元素,如果未被初始化或赋值则为随机值
(1)完全初始化所有元素。例如:
int myArray[5] = {1, 2, 3, 4, 5};

(2)部分初始化
int myArray[5] = {1, 2};
这里只有前两个数组元素被指定的值初始化,而其余(后三个)元素会被初始化为0。

(3)省略数组大小
int myArray[] = {1, 2, 3, 4, 5};
编译器会根据初始化列表的大小确定数组大小。相当于:int myArray[5] = {1, 2, 3, 4, 5};

3.访问数组元素
数组元素即为普通的变量。数组元素的使用与变量的使用一样。例如:
(1)对数组元素赋值
myArray[0] = 1;
(2)参与表达式计算
myArray[1] = myArray[0] *100;
(3)直接输出
printf(“%d”,myArray[0] );
cout<<myArray[1] <<endl;

4.数组的常见操作
(1)遍历数组:
int myArray[5] = {1, 2, 3, 4, 5};
for (int i = 0; i < 5; i++)
{
cout << myArray[i] << endl;
}
这里是每个元素独占一行。如果想在一行显示所有元素,中间用空格分割,可以用下面的代码实现:

#include<bits/stdc++.h>
using namespace std;
#define N 5
int myArray[5] = {1, 2, 3, 4, 5};
int	main() 
{
	cout<<myArray[0];
	for (int i = 1; i < 5; i++)
	{
		cout <<" "<< myArray[i];
	}
	cout<<endl;
	
	return 0;
}

(2)查找某个值是否存在。如果存在多个相同的值则返回第一次出现的位置。如果要查找的值不存在,则返回-1。参考代码如下:

#include<bits/stdc++.h>
using namespace std;
#define N 5
int myArray[5] = {1, 2, 3, 4, 5};
int	main() 
{
	int m;//要查找的值
	int p = -1;//假设要查找的值不存在
	
	cin>>m;
	for (int i = 0; i < 5; i++)
	{
		if(myArray[i]==m)
		{
			p = i;
			break;
		}
	}
	cout<<p<<endl;
	
	return 0;
}

如果存在多个相同的值,要返回最后一次出现的位置该怎么办呢?我们可以从后往前来遍历数组,这样找第一次找到的位置就是正序的最后一次出现的位置。参考代码如下:

#include<bits/stdc++.h>
using namespace std;
#define N 5
int myArray[5] = {1, 2, 3, 4, 5};
int	main() 
{
	int m;//要查找的值
	int p = -1;//假设要查找的值不存在
	
	cin>>m;
	for (int i = 4; i >=0 ; i--)
	{
		if(myArray[i]==m)
		{
			p = i;
			break;
		}
	}
	cout<<p<<endl;
	
	return 0;
}

(3)查找最大/小值
在数组中查找最大值,并返回最大值所在的位置。参考代码如下:

#include<bits/stdc++.h>
using namespace std;
#define N 5
int myArray[5] = {1, 2, 3, 4, 5};
int	main() 
{
	int max = INT_MIN;//保存最大值。初始化为最小值
	int p = -1;//最大值所在的位置
	
	for (int i = 0; i <5 ; i++)
	{
		if(myArray[i]>max)
		{
			max = myArray[i];
			p = i;
		}
	}
	cout<<max<<" "<<p<<endl;
	
	return 0;
}
这里是把max变量初始化为整数中的最小值。我们也可以把max初始化为数组的第一个元素。代码如下:
#include<bits/stdc++.h>
using namespace std;
#define N 5
int myArray[5] = {1, 2, 3, 4, 5};
int	main() 
{
	int max;//保存最大值
	int p;//最大值所在的位置
	
	max = myArray[0];
	p = 0;
	for (int i = 1; i <5 ; i++)
	{
		if(myArray[i]>max)
		{
			max = myArray[i];
			p = i;
		}
	}
	cout<<max<<" "<<p<<endl;
	
	return 0;
}
思考一下:如果数组中的最大值存在多个,这个代码仍然返回的是第一个最大值所在的位置。这是因为遇到第二个最大值的时候,if语句中myArray[i]>max条件是不成立的,所以无法记录第二个最大值的位置。那么想返回最后一个最大值的位置该如何处理呢?答案是,只要把if语句中的大于号改成大于等于即可。
上面的代码其实还可以进一步优化,就是不使用max变量,只记录最大值的位置即可。比如:
#include<bits/stdc++.h>
using namespace std;
#define N 5
int myArray[5] = {1, 2, 3, 4, 5};
int	main() 
{
	int pmax;//最大值所在的位置

	pmax = 0;
	for (int i = 1; i <5 ; i++)
	{
		if(myArray[i]>myArray[pmax])
		{
			pmax = i;
		}
	}
	cout<<myArray[pmax]<<" "<<pmax<<endl;
	
	return 0;
}
关于查找最小值的方法与查找最大值的方法类似。这里给出一个参考代码:
#include<bits/stdc++.h>
using namespace std;
#define N 5
int myArray[5] = {1, 2, 3, 4, 5};
int	main() 
{
	int pmin;//最小值所在的位置

	pmin = 0;
	for (int i = 1; i <5 ; i++)
	{
		if(myArray[i]<myArray[pmin])
		{
			pmin = i;
		}
	}
	cout<<myArray[pmin]<<" "<<pmin<<endl;
	
	return 0;
}

(4)插入一个元素。
前面已经讲过数组中的所有元素都是连续存放的。那么要在数组中插入一个元素,就得先给这个元素“腾”出一个位置来。那又该如何“腾”出这个位置呢?答案就是:最后一个元素向后移动一个位置,倒数第二个元素“挪”到原来倒数第一个元素所在的位置,倒数第三个元素“挪”到原来倒数第二个数据所在的位置,以此类推,直到把要插入数据的位置空出来为止。假设我要在第p个位置,插入一个新的元素m。参考代码如下:

#include<bits/stdc++.h>
using namespace std;
#define N 10
int myArray[N] = {0,1, 2, 3, 4, 5,6,7};
int	main() 
{
	int n = 8;//数组中元素的个数
	int p;//要插入的位置,在这个位置之后插入数据
	int m;//要插入的数据
	cin>>p>>m;
	
	//把位置p+1到n-1的数据向后移动一个位置。
	for(int i = n-1;i>=p+1;i--)
	{
		myArray[i+1] = myArray[i];
	}
	
	//把新的数据插入的指定位置之后
	myArray[p+1] = m;
	
	//数组的元素个数增加1
	n++;
	
	cout<<myArray[0];
	for (int i = 1; i < n; i++)
	{
		cout <<" "<< myArray[i];
	}
	cout<<endl;
	return 0;
}

(5)删除一个元素
与插入数据正好相反,删除数据是不断地往前“挪”。从要删除的位置后第一个数据开始往前“挪”,直到最后一个元素为止。其实,数据不是被删除的,而是被后面的数据覆盖掉的。参考代码如下:

#include<bits/stdc++.h>
using namespace std;
#define N 10
int myArray[N] = {0,1, 2, 3, 4, 5,6,7};
int	main() 
{
	int n = 8;//数组中元素的个数
	int p;//要删除的位置

	cin>>p;
	
	//把位置p+1到n-1的数据向前移动一个位置。
	for(int i = p;i<n-1;i++)
	{
		myArray[i] = myArray[i+1];
	}
	
	//数组的元素个数减少1
	n--;
	
	cout<<myArray[0];
	for (int i = 1; i < n; i++)
	{
		cout <<" "<< myArray[i];
	}
	cout<<endl;
	return 0;
}

注意:当数组中数据元素很多的时候,这种移动操作是非常消耗资源的。因此有的时候,会把要删除的数据用一个不存在的值去代替。比如数组中的元素都是正整数,要删除的数据直接改为-1,这样通过减少移动数据来提高算法效率。

(4)数组排序
经典的排序算法有很多种,这里我们介绍一种最简单的排序算法——冒泡排序(Bubble Sort)。冒泡排序算法要重复地遍历要排序的数组。我们默认进行升序排序。那么第一次遍历数组时,首先第一个元素和第二个元素比较,如果不满足升序规则(即第一个元素小于第二个元素),则交换这两个元素的值。如果满足则什么都不做;然后按照上述规则,比较第二个元素和第三个元素的大小……直到比较数组的最后两个元素。遍历一次数组我们称为一趟排序。当完成第一趟排序时,数组中的最大的元素就会被排到数组的最后。换句话说,冒泡排序算法进行一趟排序就会把一个值移动到正确的位置上。那么第二趟排序的时候就可以不考虑最后这个元素,这就相当于减小了数组的规模。第一趟排序在n个数中排序,第二趟排序的时候在前n-1个元素中排序……直到数组中剩下两个元素,再做一趟排序,那么整个数组的排序工作就完成了。我们用数据来演示一下,比如原来数组中的数据是 4 3 5 2 1,那么第一趟排序时,首先4和3比较,4大于3不满足升序规则,4和3交换位置,数据的数据变为:3 4 5 2 1;然后4和5比较,满足升序规则什么都不做;5和2比较,不满足升序规则,交换顺序,数组元素变为:3 4 2 5 1;然后5和1比较,继续交换,数组元素变为:3 4 2 1 5。这时候,数组中最大的元素5已经在正确的位置上了。下一趟排序时,就不需要再考虑这个元素。
通过上面的分析我们看到,如果数组中有n个元素,那么冒泡排序第一趟排序需要比较n-1次,第二趟需要比较n-2次,……..,直到剩下两个元素,比较1次。那么一共比较了多少次呢?1+2+3+…..+(n-1) =n*(n-1)/2次。当数据多时,效率很低。数据少时可以用。参考代码如下:

#include<bits/stdc++.h>
using namespace std;
#define N 10
int myArray[N] = {7,6, 5, 4, 3, 2,1,0};
int	main() 
{
	int n = 8;//数组中元素的个数

	for(int i=0;i<n-1;i++)//n-1趟扫描
	{
		for(int j=0;j<n-i-1;j++)//没趟比较的次数越来越少
			if(myArray[j]>myArray[j+1])//不符合升序规则,交换数据
			{
				int t= myArray[j];
				myArray[j] = myArray[j+1];
				myArray[j+1] = t;
			}
			
	}
	
	cout<<myArray[0];
	for (int i = 1; i < n; i++)
	{
		cout <<" "<< myArray[i];
	}
	cout<<endl;
	return 0;
}
这里是升序(从小到大)排序,如果想改为降序(从大到小)排序只要把if语句中的大于号改为小于号即可。
这个算法一个最大的问题是,如果最初数组中的数据已经有序了,算法依然要进行n-1趟排序才会结束。那有没有办法探测数组是否已经有序,并提前退出呢?答案是有的。当数组完全有序的时候,算法中的if语句就不会被执行。那么我们就可以根据每趟排序时if语句执行的次数来判断数据是否已经有序。参考代码如下:
#include<bits/stdc++.h>
using namespace std;
#define N 10
int myArray[N] = {0,1, 2, 3, 4, 5, 6, 7};
int	main() 
{
	int n = 8;//数组中元素的个数

	for(int i=0;i<n-1;i++)//n-1趟扫描
	{
		bool flag = true;//假设数组已经有序
		for(int j=0;j<n-i-1;j++)//没趟比较的次数越来越少
			if(myArray[j]>myArray[j+1])//不符合升序规则,交换数据
			{
				flag = false;//如果交换发生则修改有序标记
				int t= myArray[j];
				myArray[j] = myArray[j+1];
				myArray[j+1] = t;
			}
			
		if(flag)//如果没有交换发生,则提前退出排序算法
			break;
			
	}
	
	cout<<myArray[0];
	for (int i = 1; i < n; i++)
	{
		cout <<" "<< myArray[i];
	}
	cout<<endl;
	return 0;
}

(5)计算数组的大小
可以使用 ​sizeof​运算符来获取数组的大小。注意,​sizeof​返回的是数组占用的总字节数,因此需要除以单个元素的字节数来得到元素的个数。参考代码如下:

int myArray[5] = {1, 2, 3, 4, 5};
int size = sizeof(myArray) / sizeof(myArray[0]);
cout << “Array size: ” << size; // 输出5

(6)动态分配一维数组
有的时候需要在程序运行时根据需要来确定数组的大小。可以使用new运算符或者malloc()函数来实现:

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

int main()
{
	int size;
	cin >> size;
	int *array = new int[size]; // 动态分配一个大小为 ​size​的整型数组,
					//并返回一个指向该数组的指针。

	// 初始化数组
	for (int i = 0; i < size; ++i)
	{
		array[i] = i * 10;
	}

	delete[] array;	// 释放动态分配的内存,确保没有内存泄漏。
	return 0;
}
也可以:
#include <bits/stdc++.h>
using namespace std;

int main()
{
	int size;
	cin >> size;
	int *array = (int *)malloc(size * sizeof(int)); // 动态分配一维数组

	// 检查内存是否成功分配
	if (array == nullptr)
	{
		cerr << "Memory allocation failed!" << endl;
		return 1;
	}
	// 初始化数组
	for (int i = 0; i < size; ++i)
	{
		array[i] = i * 10;
	}

	free(array);	// 释放动态分配的内存
	return 0;
}

6.注意事项
(1)C++不会检测数组越界的情况。因此代码如果访问或修改超出数组范围的元素会导致未定义行为,可能会导致程序崩溃或产生不可预测的结果。
(2)C++中的数组大小在编译时确定,不能动态改变。因此在声明数组时,要一次申请够用(当然也不要查过实际需求过多)。如果需要动态大小的数组,可以考虑使用 STL中的数据结构:vector​。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呱呱呱~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值