【C++】STL容器实现二维数组

导言

数组,想必大家并不陌生,C语言中我们经常会定义各种数组,自然也包括二维数组。
所有数组都有一个特性,那就是我们在定义他们的时候必须限制他的大小,这是不能徇私的,大家都一样,必须遵守这个规则。

01.一个问题

如果在工作中要你用C++实现二维数组,并且这个二维数组还是动态可变的,你会怎么做?

如果说有一个东西,能够自动检测申请的空间够不够,不够就重新申请更大的空间,然后移动所有的数据,是不是就能解决这个问题。

这个问题,很久之前,软件界的前辈在设计STL标准的时候就已经解决了这个问题,提供了一个动态数组,就是我们工作中经常用的容器之一:vector容器。

vector容器是一种类数组的容器,封装好的数组,非常的好用,主要是,我们不用担心内存越界、空间不够等等问题。

至于STL,我后面有空会写各种STL基本的用法,为了能够在C++编程中更上一层楼,特意去买了STL源码剖析,后面我们在慢慢道来。

02.用法一(我没用过,借鉴知识点)

2.1二维vector的定义

#include <iostream>
#include <vector> //如果想用vector必须包含对应头文件
using namespace std;

int main()
{
	//双vector里面一定带空格区分,以免出问题。
	vector<vector<int> > vec(m); //这里m不能少,我没试过,你们可以试下这种写法
	
	//这里创建一个m*n的二维vector
	for(int i = 0;i<m;i++)
	{//这里是给内层vector定义大小。默认是0,这里n是个数,不是值
		vec[i].resize(n);
	}
	
	system("pause");
	return 0;
}

2.2 二维vector实例

//下面就是二维vector,按照上面的方式的一个实例,请看

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

int main()
{
	vector<vector<int> > vec(4);
	for(int i = 0;i<4;i++)
	{
		vec[i].resize(5);
	}
	//输出二维数组的行和列
	cout << "row(行):" << vec.size() << "col(列):" << vec[0].size() << endl; //输出4和5

	//输出二维vector的所有值
	for(int i = 0; i < 4; i++)
	{
		for(int j = 0; j < 5; j++)
		{ 
			cout << vec[i][j];
		}
		cout << endl; //打完一行就换行
	}
	
	system("pause");
	return 0;
}

03.vector遍历方法

下面我展示两种遍历vector或者说容器的方法:方便待会写的代码不用多做解释。
其实,除了这两种还有一种叫做迭代器遍历,但是这个我准备STL再说.

3.1 下标遍历方法(常用)

#include <iostream>
#include <vector>
using namespace std;
//下面定义一个宏
#define ROW 10

//traverse vector<vector<int> >
void TraverseVec(vector<int>& vec)
{
	//1.parameter check(参数检查,好习惯)
	if(vec.size() == 0)
	{
		return;
	}
	//2.start traverse (开始遍历)
	for(int i = 0; i < ROW; i++)
	{
		cout << vec[i] << endl;
	}
}

int main()
{
	vector<int> vec;
	for(int i = 0; i < ROW; i++)
	{
		vec.push_back(i); //尾插法,STL中再说,就是给vec中赋值
	}
	
	TraverseVec(vec);
	
	system("pause");
	return 0;
}

3.2 区间迭代(C++11新特性)

这也是我最喜欢的一种遍历容器的方法,超级好用,谁用谁喜欢。

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

int main()
{
	//这个方法太好用了,所以不用函数,简单快捷.
	vector<int> vec;
	vec.push_back(1);
	vec.push_back(2);
	vec.push_back(3);
	vec.push_back(4);
	vec.push_back(5);

	//traverse
	for(int a : vec)
	{
		cout << a;
	}
	cout << endl; //换行
	
	system("pause");
	return 0;
}

04.Working遇到的二维vector例子

下面的代码是MFC中的,C++语言编的程。看得懂看,看不懂跳过。

//读取打标数据函数
BOOL COnLineProcessParaDialog::ReadFolderPathData(CString strPassFilePath,CString sFileName)
{
	theApp.m_Pref.m_Advance.data.MarkData.clear();
	theApp.m_Pref.m_Advance.data.v_TargetFilePath.clear();
	if(strPassFilePath.Right(1) != "\\")
	{
		strPassFilePath += "\\";
	}
	strPassFilePath += "*.txt";
	CString startPath = strPassFilePath;
	CFileFind finder; //查找类对象

	BOOL bworking = finder.FindFile(startPath); //查找当前目录下是否有文件或者目录
	while(bworking)
	{
		bworking = finder.FindNextFile(); //使用下面的IsDots()必须有此函数(前面)
		if(!finder.IsDots())
		{
			if(!finder.IsDirectory())
			{//是文件
				CString strFileName = finder.GetFileName(); //获取文件名字
				theApp.m_Pref.m_Advance.data.strQRCode = strFileName;
				if(strFileName == sFileName) //QRCodeName and strFileName is or no equality?
				{
					CString TeamFilePath = finder.GetFilePath(); //获取文件完整路径
					CString DesFilePath = TeamFilePath;
					DesFilePath.MakeLower(); //转换为小写字母
					if(DesFilePath.Right(4) == _T(".txt"))
					{
					   //目标文件
					   heApp.m_Pref.m_Advance.data.v_TargetFilePath.push_back("TeamFilePath");
					}
					break;
				}
				else
				{
					continue;
					//本来这里是用的递归遍历所有文件夹的,但是,考虑到不用,而且递归对空间的占用率就去掉了。
				}
			}
		}
	}
	finder.Close(); //close finder
	
	if(theApp.m_Pref.m_Advance.data.v_TargetFilePath.size() == 0)
	{
		return FALSE;
	}

	//deal vessel data, read data
	vector<CString> v1 = theApp.m_Pref.m_Advance.data.v_TargetFilePath;
	CString strLine = "";
	int nTime = 0;
	const char* s = NULL;
	vector<char> tempLine;
	vector<vector<char> > StrLine;
	//这里就用到了上面的方法
	for(CString DealPath : v1)
	{
	//这里是调用的公司自己封装的文件操作函数,不用管,只是对系统文件操作函数进行二次封装
		CStdFile cf(DealPath);
		if(!cf.Open())
		{//open failed
			return FALSE;
		}
		
		CDebug::GetObjectA()->Printf(CDebug::IL_INFO,"读取文件为"+DealFath);
		while(cf.ReadLine(strLine))
		{//get Data
			s = strLine.GetBuffer(strLine.GetLength()); //change data
			//analysis data
			while(*s != '\0')
			{
				if(*s != ',')
				{
					tempLine.push_back(*s);
					//nTime = tempLine.size();
					s++;
				}
				else
				{
					s++;
				}
			}

			StrLine.push_buck(tempLine);
			tempLine.clear();
			strLine = ""; //set string empty,reserved next string.
		}
		cf.Close(); //close file
	}
	//traverse vessel try data read rule -> vector
	for(int j = 0; j < StrLine[0].size(); j++)
	{
		for(int i = 0; i < StrLine.size(); i++)
		{
			if(j % 2 == 0)
			{
				theApp.m_Pref.m_Advance.data.MarkData.push_back(StrLine[i][j]);
			}
			else
			{
				theApp.m_Pref.m_Advance.data.MarkData.push_back(StrLine[StrLine.size()-1 - i][j]);
			}
		}
	}
	return TRUE;
}

上面设计到很多其他文件或者说类的东西,看不懂就不用管,写出来只是想说还有其他写法,不在定义二维vector时给默认的值也是可以的,而且程序一样的稳定,不会有问题。

05.总结

上面列举了两种方式,和遍历容器的方法。如果觉得这个MFC这部分不好看,你们自己建立一个空项目也是可以这么测试的,当然,不用写这么多,这个函数的逻辑比较复杂。
vector容器是我们工作中最常用的,学了STL,但是我工作中基本只用两个容器就可以搞定,一个vector(数组),一个list(链表),他们的区别我就不说了,跟数组与链表一样的。
基础是死的,需求是活的,只有能用基础完成需求,才能说自己掌握了这个方法,这个知识点。

收藏家

06.结语

上面就是STL容器实现二维数组的全部内容,相较其他的博主,自认为还是不是太差,希望大家能看懂,要是遇到看不懂的,可以直接下面评论或者直接私我,都会回复的。

版权声明:创作不易,转载请注明出处,谢谢各位捧场。

猜你喜欢

转载自blog.csdn.net/m0_43458204/article/details/106794703
今日推荐