数据结构和算法(04)---数组,动态内存,vector(c++)
文章目录
目录
- 数据结构:
- 逻辑结构:数组,栈,队列,字符串,树,图
- 存储结构:顺序存储,链式存储
- C++常用的数据结构有:string , stack , queue , deque , vector , list , map , iterators.
数组
1.数组的申明
#include <iostream>
using namespace std;
#include <iomanip>
using std::setw;
int main ()
{
int n[ 10 ]; // n 是一个包含 10 个整数的数组
// 初始化数组元素
for ( int i = 0; i < 10; i++ )
n[ i ] = i + 100; // 设置元素 i 为 i + 100
cout << "Element" << setw( 13 ) << "Value" << endl;
// 输出数组中每个元素的值
for ( int j = 0; j < 10; j++ )
cout << setw( 7 )<< j << setw( 13 ) << n[ j ] << endl;
}
运行结果:
Element Value
0 100
1 101
2 102
3 103
4 104
5 105
6 106
7 107
8 108
9 109
2.数组的初始化
(1)Array 直接初始化 char 数组是特殊的,这种初始化要记得字符是以一个 null 结尾的
char a1[] = {'C', '+', '+'}; // 初始化,没有 null
char a2[] = {'C', '+', '+', '\0'}; // 初始化,明确有 null
char a3[] = "C++"; // null 终止符自动添加
const char a4[6] = "runoob"; // 报错,没有 null 的位置
a4 是错误的,虽然 a4 包括 6 个直接字符,但是 array 大小是 7:6个字符 + 一个null。正确的是:
const char a4[7] = "runoob";
(2)Array 是固定大小的,不能额外增加元素.当我们想定义不固定大小的字符时,可以使用 vector(向量) 标准库
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 创建向量用于存储整型数据
vector<int> vec;
int i;
// 显示 vec 初始大小
cout << "vector size = " << vec.size() << endl;
// 向向量 vec 追加 5 个整数值
for(i = 0; i < 5; i++)
vec.push_back(i);
// 显示追加后 vec 的大小
cout << "extended vector size = " << vec.size() << endl;
}
vec 的大小随着 for 循环的输入而增大。
执行以上代码,输出结果:
vector size = 0
extended vector size = 5
(3)动态数组
动态数组指的是在数组使用的时候才分配存储空间,而不是像静态数组那样一开始就分配好存储空间的。
静态 int array[100]; 定义了数组 array,并未对数组进行初始化
静态 int array[100] = {1,2}; 定义并初始化了数组 array
动态 int* array = new int[100]; delete []array; 分配了长度为 100 的数组 array
动态 int* array = new int[100]{1,2}; delete []array; 为长度为100的数组array初始化前两个元素
3.二维数组
多维数组最简单的形式是二维数组。一个二维数组,在本质上,是一个一维数组的列表。声明一个 x 行 y 列的二维整型数组,形式如下:
type arrayName [ x ][ y ];
其中,type 可以是任意有效的 C++ 数据类型,arrayName 是一个有效的 C++ 标识符。
一个二维数组可以被认为是一个带有 x 行和 y 列的表格。下面是一个二维数组,包含 3 行和 4 列:
初始化二维数组
int a[3][4] = {
{0, 1, 2, 3} , /* 初始化索引号为 0 的行 */
{4, 5, 6, 7} , /* 初始化索引号为 1 的行 */
{8, 9, 10, 11} /* 初始化索引号为 2 的行 */
};
内部嵌套的括号是可选的
int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
访问二维数组元素
#include <iostream>
using namespace std;
int main ()
{
// 一个带有 5 行 2 列的数组
int a[5][2] = { {0,0}, {1,2}, {2,4}, {3,6},{4,8}};
// 输出数组中每个元素的值
for ( int i = 0; i < 5; i++ ){
for ( int j = 0; j < 2; j++ )
{
cout << "a[" << i << "][" << j << "]: ";
cout << a[i][j]<< endl;
}
}
}
a[0][0]: 0
a[0][1]: 0
a[1][0]: 1
a[1][1]: 2
a[2][0]: 2
a[2][1]: 4
a[3][0]: 3
a[3][1]: 6
a[4][0]: 4
a[4][1]: 8
4.指向数组的指针
数组名是一个指向数组中第一个元素的常量指针(无法对数组名重新赋值)。因此,在下面的声明中:
double balance[50];
balance 是一个指向 &balance[0] 的指针,即数组 balance 的第一个元素的地址。因此,下面把 p 赋值为 balance 的第一个元素的地址:
double *p;
double balance[10];
p = balance;
- 使用数组名作为常量指针是合法的,反之亦然。因此,*(balance + 4) 是一种访问 balance[4] 数据的合法方式。
- 一旦您把第一个元素的地址存储在 p 中,您就可以使用 * p、* (p+1)、* (p+2) 等来访问数组元素
#include <iostream>
using namespace std;
int main ()
{
// 带有 5 个元素的双精度浮点型数组
double balance[5] = {1000.0, 2.0, 3.4, 17.0, 50.0};
double *p;
p = balance;
// 输出数组中每个元素的值
cout << "使用指针的数组值 " << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "*(p + " << i << ") : ";
cout << *(p + i) << endl;
}
cout << "使用 balance 作为地址的数组值 " << endl;
for ( int i = 0; i < 5; i++ )
{
cout << "*(balance + " << i << ") : ";
cout << *(balance + i) << endl;
}
return 0;
}
使用指针的数组值
*(p + 0) : 1000
*(p + 1) : 2
*(p + 2) : 3.4
*(p + 3) : 17
*(p + 4) : 50
使用 balance 作为地址的数组值
*(balance + 0) : 1000
*(balance + 1) : 2
*(balance + 2) : 3.4
*(balance + 3) : 17
*(balance + 4) : 50
5.传递数组给函数
- C++ 不允许向函数传递一个完整的数组作为参数
- 但是,您可以通过指定不带索引的数组名来传递一个指向数组的指针。
如果您想要在函数中传递一个一维数组作为参数,您必须以下面三种方式来声明函数形式参数,这三种声明方式的结果是一样的,因为每种方式都会告诉编译器将要接收一个整型指针。同样地,您也可以传递一个多维数组作为形式参数
方式1: 形式参数是一个指针
void myFunction(int *param){ }
方式2:形参为一个已经定义了大小的数组
void myFunction(int param[10]){ }
方式3: 形式参数是一个未定义大小的数组
void myFunction(int param[]){ }
实例:把数组作为参数,同时还传递了另一个参数,根据所传的参数,会返回数组中各元素的平均值
#include <iostream>
using namespace std;
// 函数声明
double getAverage(int arr[], int size);
int main ()
{
int balance[5] = {1000, 2, 3, 17, 50}; // 带有 5 个元素的整型数组
double avg;
avg = getAverage(balance, 5) ; // 传递一个指向数组的指针作为参数
cout << "平均值是:" << avg << endl; // 输出返回值
}
double getAverage(int arr[], int size)
{
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i)
sum += arr[i];
avg = double(sum) / size;
return avg;
}
平均值是:214.4
动态内存
了解动态内存在 C++ 中是如何工作的是成为一名合格的 C++ 程序员必不可少的。C++ 程序中的内存分为两个部分:
- 栈:在函数内部声明的所有变量都将占用栈内存。
- 堆:这是程序中未使用的内存,在程序运行时可用于动态分配内存。
很多时候,您无法提前预知需要多少内存来存储某个定义变量中的特定信息,所需内存的大小需要在运行时才能确定。
- 在 C++ 中,您可以使用特殊的运算符为给定类型的变量在运行时分配堆内的内存,这会返回所分配的空间地址。这种运算符即 new 运算符。
- 如果您不需要动态分配内存,可以使用 delete 运算符,删除之前由 new 运算符分配的内存。
1.new ,delete运算符
#include <iostream>
using namespace std;
int main ()
{
double* pvalue = NULL; // 初始化为 null 的指针
pvalue = new double; // 为变量请求内存
*pvalue = 29494.99; // 在分配的地址存储值
cout << "Value of pvalue : " << *pvalue << endl;
delete pvalue; // 释放内存
}
Value of pvalue : 29495
2.数组的动态内存分配
二维数组
二维数组其实可以看成2个一维的数组,所以初始化也需要分成2步来初始化,先初始化行,然后初始化列。
int **array
// 假定数组第一维长度为 m, 第二维长度为 n
// 动态分配空间
array = new int *[m]; //初始化行
//对每行初始化列
for( int i=0; i<m; i++ )
{
array[i] = new int [n] ;
}
//释放
for( int i=0; i<m; i++ )
{
delete [] arrar[i];
}
delete [] array;
实例
#include <iostream>
using namespace std;
int main()
{
int **p;
int i,j; //p[4][8]
//开始分配4行8列的二维数据
p = new int *[4];
for(i=0;i<4;i++)
p[i]=new int [8];
for(i=0; i<4; i++){
for(j=0; j<8; j++)
p[i][j] = j*i;
}
//打印数据
for(i=0; i<4; i++){
for(j=0; j<8; j++)
{
if(j==0) cout<<endl;
cout<<p[i][j]<<"\t";
}
}
//开始释放申请的堆
for(i=0; i<4; i++){
delete [] p[i];
}
delete [] p;
}
运行结果:
0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7
0 2 4 6 8 10 12 14
0 3 6 9 12 15 18 21
vector
1.vector基本操作
在c++中,vector是一个十分有用的容器。
- 作用:它能够像容器一样存放各种类型的对象,简单地说,vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。
- vector在C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。
![]()
实例
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> vec; // 创建一个向量存储 int
int i;
cout << "vector size = " << vec.size() << endl; // 显示 vec 的原始大小
for(i = 0; i < 5; i++) // 推入 5 个值到向量中
vec.push_back(i);
cout << "extended vector size = " << vec.size() << endl; // 显示 vec 扩展后的大小
for(i = 0; i < 5; i++)
cout << "value of vec [" << i << "] = " << vec[i] << endl; // 访问向量中的 5 个值
// 使用迭代器 iterator 访问值
vector<int>::iterator v = vec.begin();
while( v != vec.end()) {
cout << "value of v = " << *v << endl;
v++;
}
}
vector size = 0
extended vector size = 5
value of vec [0] = 0
value of vec [1] = 1
value of vec [2] = 2
value of vec [3] = 3
value of vec [4] = 4
value of v = 0
value of v = 1
value of v = 2
value of v = 3
value of v = 4
2.vector使用
特别注意
- 1、如果你要表示的向量长度较长(需要为向量内部保存很多数),容易导致内存泄漏,而且效率会很低;
- 2、Vector作为函数的参数或者返回值时,需要注意它的写法:
double Distance(vector< int >&a, vector< int >&b) 其中的“&”绝对不能少!!!- 3.vector的元素不仅仅可以是int,double,string,还可以是结构体,但是要注意:结构体要定义为全局的,否则会出错。
算法
1.使用reverse将元素翻转,需要头文件#include< algorithm >
reverse(vec.begin(),vec.end()); //将元素翻转,即逆序排列!
在vector中,如果一个函数中需要两个迭代器,一般后一个都不包含
2.使用sort排序:需要头文件#include< algorithm >,
sort(vec.begin(),vec.end()); //默认是按升序排列,即从小到大
可以通过重写排序比较函数按照降序比较,如下:
//定义排序比较函数:
bool Comp(const int &a,const int &b)
{
return a>b;
}
//调用时
sort(vec.begin(),vec.end(),Comp) //这样就降序排序
3.vector动态二维数组 初始化和赋值
一维数组
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v={1,2,3};
cout<<v[2]<<endl;
v.push_back(3);
cout<<v[3]<<endl;
}
3
3
二维数组
(1)第1种方法:通过 resize( ) 的形式改变行列数
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int array_temp[4][4]={1,2,8,9,
2,4,9,12,
4,7,10,13,
6,8,11,15
};
int i,j;
//得到一个 4行4列的数组,通过resize()的形式改变行列数
vector<vector<int> > array(4);
for(i=0;i<array.size();i++)
array[i].resize(4);
for(i = 0; i < array.size(); i++){
for (j = 0; j < array[0].size();j++)
array[i][j] = array_temp[i][j];
}
cout<<array[2][3]<<endl;
}
(2)第2种方法:通过 push_back( )
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int array_temp[4][4]={1,2,8,9,
2,4,9,12,
};
int i,j;
vector<vector<int> > array;
vector<int> a;
vector<int> b;
for(i=0;i<4;i++)
a.push_back(array_temp[0][i]);
for(i=0;i<4;i++)
b.push_back(array_temp[1][i]);
cout<<"a[1]="<<a[1]<<endl;
cout<<"b[2]="<<b[2]<<endl;
array.push_back(a);
array.push_back(b);
cout<<array.size()<<endl;
cout<<array[0].size()<<endl;
cout<<array[1][2]<<endl;
}
(3)第3种方法: 使用vector < int* > v1;
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int out[3][2] = { 1, 2,
3, 4,
5, 6 };
vector <int*> v1; //相当于每一行是一个一维的数组,每个元素保存的是该数组的第一个元素地址
// vector <vector<int>> v1; //这样是错误的
v1.push_back(out[0]); //压入第一行元素
v1.push_back(out[1]);
v1.push_back(out[2]);
cout << v1[0][0] << endl; //1
cout << v1[0][1] << endl; //2
cout << v1[1][0] << endl; //3
cout << v1[1][1] << endl; //4
cout << v1[2][0] << endl; //5
cout << v1[2][1] << endl; //6
}