本文是个人学习C++的学习记录,没学习过C++,主要通过复现程序,解决相关问题学习。
对很多概念的理解大都是通过搜索再加自圆其说,所以肯定有很多错误和理解不到位的地方,还望大佬们多多指点,小白们相互讨论,共勉共进。
求矩阵的四连通域,主要参考博文:
求01矩阵的连通域(c++版本)_wphkadn的博客-CSDN博客_c++ 连通域
程序思路:
1、从矩阵的第一个元素开始访问,当为1时,进入连通域分析
2、分析此元素位置上下左右的元素是否为1,若为1,将对应坐标添加到此元素的连通域下
3、继续循环遍历矩阵的下一个元素
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct Point
{
int r;
int c;
Point(int r_, int c_) : r(r_), c(c_){}
Point(const Point& p) : r(p.r), c(p.c){}
};
class Solution
{
public: //全局变量。全局变量既可以是某对象函数创建,也可以是在本程序任何地方创建。全局变量是可以被本程序所有对象或函数引用。
int m;
int n;
//判断索引点不要越界,该点之前没有访问过,该点是有效的点
bool isvalid(int i, int j, vector<vector<int>>& matrix, vector<vector<bool>>& mask)
{
return i>=0 && i<m && j>=0 && j<n && !mask[i][j] && matrix[i][j]==1;
}
//将合适的点加入到队列中,并标记其被访问过
void add(int i, int j, vector<vector<int>>& matrix, queue<Point>& q, vector<vector<bool>>& mask)
{
if(isvalid(i, j, matrix, mask))
{
q.push(Point(i,j));
mask[i][j]=true;
}
}
//主代码,两重for循环+一个queue
vector<vector<Point>> bwlabel(vector<vector<int>> &matrix)
{
m=matrix.size();
n=matrix[0].size();
vector<vector<Point>> res;
vector<Point> tmp;
vector<vector<bool>> mask(m, vector<bool>(n,false));
for(int i=0; i<m;i++)
{
for(int j=0; j<n; j++)
{
if(mask[i][j] || matrix[i][j] == 0)
continue;
tmp.clear();
queue<Point> q;
q.push(Point(i,j));
mask[i][j] = true;
while(!q.empty())
{
Point t = q.front();
q.pop();
tmp.push_back(t);
//根据四邻域定义得来
add(t.r-1, t.c, matrix, q, mask);
add(t.r+1, t.c, matrix, q, mask);
add(t.r, t.c-1, matrix, q, mask);
add(t.r, t.c+1, matrix, q, mask);
}
res.push_back(tmp);
}
}
return res;
}
};
int main()
{
vector<vector<int>> m = {
{1,1,0,0,0},
{1,0,1,0,0},
{0,1,1,0,0},
{0,0,0,1,0},
{0,0,0,0,1},
{0,0,0,0,0}
};
vector<vector<int>> n = {{}};
Solution s;
vector<vector<Point>> res = s.bwlabel(m);
vector<vector<Point>> rss = s.bwlabel(n);
return 0;
}
程序相关知识点:
1、struct point
用结构体Struct定义一个新的数据类型point,{}中是对这个新的数据类型的描述,根据描述我理解point记录一个点的坐标信息。
代码中r_没有什么特殊的意义,仅仅是为了与r做一个区分
Point(x0,y0):x(x0),y(y0){}
2、函数及函数的调用
class是类函数,函数的名称为Solution,可以看做为一类函数的集合,这个函数包内有很多的子函数,每个子函数会完成一定的功能。譬如你想要实现加法的运算,那就需要调用计算这个函数包里面的一个用来计算两数之和功能的子函数得到你想要的结果。
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
class Solution //Solution的函数包
{
public:
int m;
int n;
vector<vector<Point>> bwlabel(vector<vector<int>> &matrix) //隶属于类函数Solution下的bwlabel子函数
{
//定义了函数实现的功能
return res; //函数的返回值为res
}
};
int main() //主函数调用函数包实现数据处理
{
vector<vector<int>> m = {
{1,1,0,0,0},
{1,0,1,0,0},
{0,1,1,0,0},
{0,0,0,1,0},
{0,0,0,0,1},
{0,0,0,0,0}
};
vector<vector<int>> n = {{}};
Solution s;
vector<vector<Point>> res = s.bwlabel(m); //想要使用bwlabel函数对数据进行处理,调用方式为调用类函数下的子函数————s.bwlabel,()内的代表输入变量,=是将函数的返回值(也即处理结果)赋值给变量res。
vector<vector<Point>> rss = s.bwlabel(n);
return 0;
}
3、bool(布尔)逻辑判断
这个判断函数的名称为isvalid,输入量为()内的元素,判断条件为return后的逻辑运算,条件符合返回真(1),不符合返回假(0)
//判断索引点不要越界,该点之前没有访问过,该点是有效的点
bool isvalid(int i, int j, vector<vector<int>>& matrix, vector<vector<bool>>& mask)
{
return i>=0 && i<m && j>=0 && j<n && !mask[i][j] && matrix[i][j]==1;
}
4、向量Vector
a、定义:
vector< vector<int>> mask(m, vector<int>(n))定义了一个vector容器名称为mask,元素类型为vector<int>,初始化为包含m个vector<int>对象,每个对象都是一个新创立的vector<int>对象的拷贝,而这个新创立的vector<int>对象被初始化为包含n个0。
b、输出
学习C++ - 向量(vector)!你今天努力了吗? - 知乎
需要逐个元素进行输出,没有像MATLAB那么方便。
int i, j;
for(i = 0; i < res.size()-3; i++)
{
for(j = 0; j < res[i].size(); j++)
cout << res[i][j] << " ";
cout << "\n";
}
5、队列quence
数据结构:栈和队列(Stack & Queue)【详解】_UniqueUnit的博客-CSDN博客_数据结构栈和队列
push_back对应vector系列,push对应的stack与queue系列
vector:q.push_back();//在Vector最后添加一个元素
stack:q.push();//在栈顶增加元素。(栈顶进出)
queue:q.push();//将元素接到队列的末端。(队列尾进头出,后进后出)
- push() 在队尾插入一个元素
- pop() 删除队列第一个元素
- size() 返回队列中元素个数
- empty() 如果队列空则返回true
- front() 返回队列中的第一个元素
- back() 返回队列中最后一个元素
6、函数整体结构理解
有了这些知识基础后,程序就容易理解了
class Solution中分为三个函数,bool isvalid函数给出连通域判断条件,add函数调用判断条件统计连通域信息,bwlabel函数确定1后调用add进行四连通域判断,遍历二维向量,逐一确定连通域。
主函数main给出待判断的矩阵,采用类函数s的bwlabel进行矩阵连通域判断。
OK,感谢在解决问题过程中各位大佬的帮助,如果我的回答帮助到你,还麻烦给我点赞加油呀~~