最小二乘平面拟合(高斯牛顿法)

欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。

本期话题:最小二乘平面拟合

背景

ptb认证

ptb是对几何体拟合算法的认证。

主要涉及3D直线,3D圆,平面,球,圆柱,锥。

官方会给出点云信息,由用户将拟合结果上传到官方服务器进行对比答案,返回结果。

拟合有很多种度量标准,不同的标准出来的答案不可能完全精确。所以,要通过认证必须用官方给定的度量方法,具体可以参考论文。

认证精度要求

在这里插入图片描述
对于位置类型,比如圆心,直线的点等,误差不能超过0.0001mm。

对于角度,比如圆锥的开角,误差不能超过0.0000001rad。

对于方向,与标准值夹角不能直过0.0000001rad。

对于半径,误差不能超过0.0001mm。

学习资料

论文资料
Forbes, Alistair B.: Least-squares best fit geometric elements, NPL Report DITC 140/89 , ISSN
0262-5369, 40 pages, revised edition, 1991

由NPL发表。里面介绍了所有ptb认证的拟合算法。

平面拟合输入和输出要求

输入

  1. 8到50个点,全部采样自平面上。
  2. 每个点3个坐标,坐标精确到小数点后面20位。
  3. 坐标单位是mm, 范围[-500mm, 500mm]。

tips
输入虽然是严格来自平面,但是由于浮点表示,记录的值和真实值始终是有微小的误差,点云到拟合平面的距离不可能完全为0。

输出

  1. 平面上1点p,用三个坐标表示。
  2. 平面法向k,用三个坐标表示,需要单位化。

精度要求

  1. p点到标准平面距离不能超过0.0001mm。
  2. k与标准法向的夹角不能超过0.0000001rad。

平面优化标函数

根据论文,直线拟合转化成数学表示如下:

平面参数化表示

  1. 平面上1点X0 = (x0, y0, z0)。
  2. 方向单位向量A=(a,b,c)。

点到平面距离

第i个点 pi(xi, yi, zi)。

根据点乘得到距离

d i = ∥ ( p i − X 0 ) ⋅ A ∥ ∥ A ∥ d_i = \frac { \left \| (p_i-X_0)\cdot A \right \|}{\left \| A \right \|} di=A(piX0)A

展开一下:

d i = a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 d_i = \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)} {\sqrt{a^2+b^2+c^2}} di=a2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)

最小二乘优化能量方程

能量方程 E = f ( X 0 , A ) = ∑ 1 n d i 2 E=f(X0, A)=\displaystyle \sum _1^n {d_i^2} E=f(X0,A)=1ndi2

上式是一个6元二次函数中,X0, A是未知量,拟合平面的过程也可以理解为优化X0, A使得方程E最小。

拟合&测试基类设计

基类主要放一些公共方法和规定具体实现类要实现的算法。

具体在调用时,都用基类为载体,减少代码量。

拟合基类

#include <Eigen/Core>
#include <vector>
#include "GeometryTypes.h"


namespace Fitting {
	using Matrix = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
	/* getCenter
		获取点云中心
	 */
	Eigen::Vector3d getCenter(const std::vector<Eigen::Vector3d>& points);

	/* moveCenter
	* 将中心移至0点
	*/
	void moveCenter(const Eigen::Vector3d center, std::vector<Eigen::Vector3d>& points);

	/* getRotationByOrient(Eigen::Vector3d orient);
	* 返回一个旋转矩阵使得向量与Z轴平行
	*/ 
	Eigen::Matrix3d getRotationByOrient(Eigen::Vector3d orient);
	class FittingBase {
	protected:
		Eigen::Matrix3d U;
		std::vector<Eigen::Vector3d> transPoints;
		/* Jacobi
		* 构造jacobi矩阵
		*/
		virtual Matrix Jacobi(const std::vector<Eigen::Vector3d> &points)=0;
		
		/* findNext
		*	迭代1次得到解delta
		*/
		Eigen::VectorXd findNext(const std::vector<Eigen::Vector3d>& points);

		/* beforHook
		* 每次迭代前的准备工作
		*/
		virtual void beforHook(Eigen::VectorXd& a0, const std::vector<Eigen::Vector3d>& points)=0;
		
		/* afterHook
		* 迭代后更新答案
		*/
		virtual void afterHook(const Eigen::VectorXd& xp)=0;

		
		/* 获取 d数组
		*/
		virtual Eigen::VectorXd getDArray(const std::vector<Eigen::Vector3d>& points)=0;
		 
		// GetInitFit 返回是否拟合成功
		virtual bool GetInitFit(const std::vector<Eigen::Vector3d>& points)=0;
		// iteration
		double iteration(const std::vector<Eigen::Vector3d>& points);

		/* F
		* 距离函数
		*/
		virtual double F(const Eigen::Vector3d& p)=0;

		/* 获取 最小二乘残差
		*/
		virtual double  GetError(const std::vector<Eigen::Vector3d>& points) = 0;
		/* 获取 结果
		*/
		virtual void Copy(void* ele) = 0;

	public:
		// Fitting
		double Fitting(const std::vector<Eigen::Vector3d>& points, void* ele);
	};
}

测试基类


namespace Fitting {
	const double POSITION_MAX_DST = 0.0001, ORIENTATION_MAX_DST = 0.0000001, ANGLE_MAX_DST = 0.0000001, RADIUS_MAX_DST = 0.0001;

	void writePoint(FILE *fp, const Point &p);
	void writeNumber(FILE *fp, double n);

	// 比较平面点是否一致
	bool planeCmp(const Eigen::Vector3d& vec1, const Point& p1, const Point& p2);

	// 比较直线点是否一致
	bool lineCmp(const Eigen::Vector3d &vec1, const Point &p1, const Point &p2);
	bool lineCmp2D(const Eigen::Vector3d &vec1, const Point &p1, const Point &p2);
	// 比较半径
	bool radiusCmp(double r1, double r2);
	// 比较法向是否一致
	bool orientationCmp(const Eigen::Vector3d &vec1, const Eigen::Vector3d& vec2);
	bool orientationCmp2D(const Eigen::Vector3d &vec1, const Eigen::Vector3d& vec2);
	// 比较角度
	bool angleCmp(double angle1, double angle2);
	// 比较点位置
	bool positionCmp(const Point &p1, const Point &p2);

	/*
	测试基类
	*/
	class TestBase {
	protected:
		// 测试用例路径和文件名
		string suffixName, fileName;
		vector<Point> points;
	public:
		TestBase() {}
		TestBase(string _suffixName, string _fileName): suffixName(_suffixName), fileName(_fileName) {}
		void SetFile(string _suffixName, string _fileName);

		void readPoints();
		virtual double Fitting()=0;
		virtual bool JudgeAnswer(FILE* fp) = 0;
		virtual void ReadAnswer() = 0;
		virtual void SaveAnswer(FILE* fp) = 0;
	};

}

PCA主成分分析法

学习资料:
https://www.bilibili.com/video/BV1E5411E71z/?spm_id_from=333.337.search-card.all.click&vd_source=fb27f95f25902a2cc94d4d8e49f5f777

算法过程

  1. 计算出所有点平均值 c e n t e r i d ( x ‾ , y ‾ , z ‾ ) centerid(\overline x,\overline y,\overline z) centerid(x,y,z) , 作为平面上1点。
  2. 构建矩阵 A = [ x 1 − x ‾ y 1 − y ‾ z 1 − z ‾ x 2 − x ‾ y 2 − y ‾ z 2 − z ‾ . . . . . . . . . x n − x ‾ y n − y ‾ z n − z ‾ ] A=\begin {bmatrix} x_1-\overline x& y_1-\overline y & z_1-\overline z \\ x_2-\overline x& y_2-\overline y & z_2-\overline z\\ ... & ... &... \\x_n-\overline x& y_n-\overline y & z_n-\overline z \end {bmatrix} A= x1xx2x...xnxy1yy2y...ynyz1zz2z...znz
  3. 对矩阵A进行SVD分解,取右特征值矩阵最小特征值所对应列作为平面的法向。

代码实现

代码链接:https://gitcode.com/chenbb1989/3DAlgorithm/tree/master/CBB3DAlgorithm/Fitting

#include "TestPlane.h"
#include "FittingPlanePCA.h"
#include <iostream>

namespace Gauss {

	double TestPlanePCA::Fitting() {
		return FittingPlane(points, fitResult);
	}
	bool TestPlanePCA::JudgeAnswer(FILE* fp) {
		ReadAnswer();
		if (!planeCmp(ans.Orient, ans.BasePoint, fitResult.BasePoint))return false;
		if (!orientationCmp(ans.Orient, ans.Orient))return false;
		return true;
	}
	void TestPlanePCA::ReadAnswer() {
		vector<double> nums;
		if (PointCloud::readNums((suffixName + "/answer/" + fileName + ".txt"), nums)) {
			for (int i = 0; i < 3; ++i) ans.BasePoint[i] = nums[i];
			for (int i = 0; i < 3; ++i) ans.Orient[i] = nums[3 + i];
		}
		else {
			std::cout << "read answer error" << std::endl;
		}
	}
	void TestPlanePCA::SaveAnswer(FILE* fp) {
		writePoint(fp, fitResult.BasePoint);
		writePoint(fp, fitResult.Orient);
	}
}

测试结果

https://gitcode.com/chenbb1989/3DAlgorithm/blob/master/CBB3DAlgorithm/Fitting/gauss/fitting_result/result.txt

b05 : PLANE : pass
b06 : PLANE : pass
b07 : PLANE : pass
b08 : PLANE : pass

高斯牛顿迭代法

用于解非线性最小二乘问题。同时,高斯牛顿法需要比较可靠的初值,所以寻找目标函数的初值也是一个比较关键的步骤。

基本原理

设 a = ( a 0 , a 1 , . . . , a n ) 是待求解向量, a ^ 是初始给定值, a = a ^ + Δ a , Δ a 是我们每次迭代后移动的量 设 a=(a_0, a_1,...,a_n)是待求解向量,\widehat {a} 是初始给定值,a = \widehat {a} +\Delta a, \Delta a 是我们每次迭代后移动的量 a=(a0,a1,...,an)是待求解向量,a 是初始给定值,a=a +Δa,Δa是我们每次迭代后移动的量

定义距离函数为 F ( x , a ) , d i = F ( x i , a ) , 进行泰勒 1 阶展开, F ( x , a ) = F ( x , a ^ ) + ∂ F ∂ a ^ Δ a = F ( x , a ^ ) + J Δ a 定义距离函数为 F(x, a), d_i = F(x_i, a), 进行泰勒1阶展开, F(x, a) = F(x, \widehat a) + \frac {\partial F}{\partial \widehat a}\Delta a = F(x, \widehat a) + J\Delta a 定义距离函数为F(x,a),di=F(xi,a),进行泰勒1阶展开,F(x,a)F(x,a )+a FΔa=F(x,a )+JΔa

每次迭代,其实就是希望通过调整 Δ a 使得 J Δ a = − F ( x , a ^ ) 每次迭代,其实就是希望通过调整\Delta a 使得 J\Delta a = -F(x, \widehat a) 每次迭代,其实就是希望通过调整Δa使得JΔaF(x,a )

J = [ ∂ F ( x 0 , a ) ∂ a 0 ∂ F ( x 0 , a ) ∂ a 1 . . . ∂ F ( x 0 , a ) ∂ a n ∂ F ( x 1 , a ) ∂ a 0 ∂ F ( x 1 , a ) ∂ a 1 . . . ∂ F ( x 1 , a ) ∂ a n . . . . . . . . . . . . ∂ F ( x n , a ) ∂ a 0 ∂ F ( x n , a ) ∂ a 1 . . . ∂ F ( x n , a ) ∂ a n ] J = \begin {bmatrix} \frac {\partial F(x_0, a)} {\partial a_0} & \frac {\partial F(x_0, a)} {\partial a_1} & ...& \frac {\partial F(x_0, a)} {\partial a_n} \\ \\ \frac {\partial F(x_1, a)} {\partial a_0} & \frac {\partial F(x_1, a)} {\partial a_1} & ...& \frac {\partial F(x_1, a)} {\partial a_n} \\\\ ... & ... & ...& ... \\ \\ \frac {\partial F(x_n, a)} {\partial a_0} & \frac {\partial F(x_n, a)} {\partial a_1} & ...& \frac {\partial F(x_n, a)} {\partial a_n} \end {bmatrix} J= a0F(x0,a)a0F(x1,a)...a0F(xn,a)a1F(x0,a)a1F(x1,a)...a1F(xn,a)............anF(x0,a)anF(x1,a)...anF(xn,a)

F ( x , a ^ ) = [ d 1 d 2 . . . d m ] F(x, \widehat a) = \begin {bmatrix} d_1 \\ d_2 \\... \\ d_m \end {bmatrix} F(x,a )= d1d2...dm

J Δ a = − F ( x , a ^ ) , 解出 Δ a , 更新 a = a ^ + Δ a , 持续迭代直到 Δ a 足够小 J\Delta a = -F(x,\widehat a), 解出\Delta a ,更新 a = \widehat {a} +\Delta a, 持续迭代直到\Delta a足够小 JΔa=F(x,a ),解出Δa,更新a=a +Δa,持续迭代直到Δa足够小

如何3个参数表示平面

如果直接拿6个参数去做迭代,1是比较麻烦,会出现比较难解的方向,2是平面上的点有很多个,结果不唯一。

当平面法向与Z轴偏差比较小的时候可以使用3个参数来表示。

在这里插入图片描述

如上图,绿线为Z轴,橙色线为XOY平面。

由于法向与Z轴比较相近,可以设法向为(a, b, 1), a,b 是比较小的量。

现在表示 平面还需要一个点,规定点必须在以(a,b,1)为法向过0点的直线上。

就有直线公式 x0/a=y0/b=z0/c

那么只要知道z0就可知 x0=az0, y0=bz0.

综上,可以使用a, b, z0 表示一个法向与Z轴相近的 平面。

算法描述

Ji, di的计算。
由于算法是要将法向旋转致Z轴再进行迭代。

即a=b=z0=x0=y0=0
c=1

对3个未知数求导结果如下:
求导后a=b=z0=x0=y0=0,c=1要代入

∂ d i ∂ z 0 = ∂ a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 ∂ z 0 ∣ z 0 = 0 = − 1 \frac {\partial d_i} {\partial z0}=\frac {\partial \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)}{\sqrt{a^2+b^2+c^2}}} {\partial z0}_{|z0=0} = -1 z0di=z0a2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)z0=0=1

∂ d i ∂ a = ∂ a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 ∂ a ∣ a = 0 = x i \frac {\partial d_i} {\partial a}=\frac {\partial \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)}{\sqrt{a^2+b^2+c^2}}} {\partial a}_{|a=0} = x_i adi=aa2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)a=0=xi

∂ d i ∂ b = ∂ a ( x i − x 0 ) + b ( y i − y 0 ) + c ( z i − z 0 ) a 2 + b 2 + c 2 ∂ b ∣ b = 0 = y i \frac {\partial d_i} {\partial b}=\frac {\partial \frac {a(x_i-x_0) + b(y_i-y_0) + c(z_i-z_0)}{\sqrt{a^2+b^2+c^2}}} {\partial b}_{|b=0} = y_i bdi=ba2+b2+c2 a(xix0)+b(yiy0)+c(ziz0)b=0=yi

d i = z i d_i =z_i di=zi

  1. 确定平面初值

  2. 将直线通过刚体变换U至Z轴,U的构建可以参考代码
    [ x i y i z i ] = U ⋅ ( [ x i y i z i ] − [ x 0 y 0 z 0 ] ) \begin {bmatrix}x_i \\ y_i \\ z_i \end {bmatrix} = U \cdot \left (\begin {bmatrix}x_i \\ y_i \\ z_i \end {bmatrix}- \begin{bmatrix}x_0 \\ y_0 \\ z_0 \end {bmatrix}\right ) xiyizi =U xiyizi x0y0z0

  3. 根据上述公式构建 J ⋅ ( [ p z 0 p a p b ] ) = − D = − [ d 0 d 1 . . . d n ] J \cdot \left(\begin {bmatrix}p_{z_0} \\ p_{a}\\p_{b} \end {bmatrix} \right)=-D=-\begin {bmatrix}d_0 \\ d_1\\...\\d_n \end {bmatrix} J pz0papb =D= d0d1...dn

  4. 求解 Δ p \Delta p Δp

  5. 更新解
    [ x 0 y 0 z 0 ] = [ x 0 y 0 z 0 ] + U T ⋅ [ p a ∗ p z 0 p b ∗ p z 0 p z 0 ] \begin {bmatrix}x_0 \\ y_0 \\ z_0 \end {bmatrix} = \begin {bmatrix}x_0 \\ y_0 \\ z_0 \end {bmatrix} + U^T \cdot \begin{bmatrix}p_a*p_{z_0} \\ p_b*p_{z_0} \\ p_{z_0} \end {bmatrix} x0y0z0 = x0y0z0 +UT papz0pbpz0pz0

[ a b c ] = U T ⋅ [ p a p b 1 ] . n o r m a l i z e ( ) \begin {bmatrix}a \\ b \\ c \end {bmatrix} = U^T \cdot \begin{bmatrix}p_a \\ p_b \\ 1 \end {bmatrix}.normalize() abc =UT papb1 .normalize()

  1. 重复2直到收敛

初值确定

由于点数比较少,可以枚举3个点生成平面。

代码实现

代码链接:https://gitcode.com/chenbb1989/3DAlgorithm/tree/master/CBB3DAlgorithm/Fitting

#include "FittingPlane.h"
#include "FittingPlanePCA.h"
#include <Eigen/Dense>


namespace Gauss {
	Fitting::Matrix FittingPlane::Jacobi(const std::vector<Eigen::Vector3d>& points)
	{
		Fitting::Matrix J(points.size(), 3);
		for (int i = 0; i < points.size(); ++i) {
			auto& p = points[i];
			J(i, 0) = -1;
			J(i, 1) = p.x();
			J(i, 2) = p.y();
		}
		return J;
	}
	void FittingPlane::beforHook(Eigen::VectorXd& a0, const std::vector<Eigen::Vector3d>& points)
	{
		a0.resize(3);
		a0 << 0, 0, 0;
		U = Fitting::getRotationByOrient(plane.Orient);
		for (int i = 0; i < points.size(); ++i) {
			transPoints[i] = U * (points[i] - plane.BasePoint);
		}
	}
	void FittingPlane::afterHook(const Eigen::VectorXd& xp)
	{
		plane.BasePoint += U.transpose() * Eigen::Vector3d(xp(0)*xp(1), xp(0)*xp(2), xp(0));
		plane.Orient =U.transpose()* Eigen::Vector3d(xp(1), xp(2), 1).normalized();
	}
	Eigen::VectorXd FittingPlane::getDArray(const std::vector<Eigen::Vector3d>& points)
	{
		Eigen::VectorXd D(points.size());
		for (int i = 0; i < points.size(); ++i)D(i) =points[i].z();
		return D;
	}
	bool FittingPlane::GetInitFit(const std::vector<Eigen::Vector3d>& points)
	{
		if (points.size() < 3)return false;
		plane.BasePoint = points[0];
		Point s = points[1];
		Point s1 = points[2];

		plane.Orient = (s-plane.BasePoint).cross(s1-plane.BasePoint);
		plane.Orient.normalize();

		return true;
	}
	double FittingPlane::F(const Eigen::Vector3d& p)
	{
		return Gauss::F(plane, p);
	}
	double FittingPlane::GetError(const std::vector<Eigen::Vector3d>& points)
	{
		return Gauss::GetError(plane, points);
	}
	void FittingPlane::Copy(void* ele)
	{
		memcpy(ele, &plane, sizeof(Fitting::Plane));
	}
}

测试结果

https://gitcode.com/chenbb1989/3DAlgorithm/blob/master/CBB3DAlgorithm/Fitting/gauss/fitting_result/result.txt

b05 : PLANE : pass
b06 : PLANE : pass
b07 : PLANE : pass
b08 : PLANE : pass

本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。创作不易,帮忙点击公众号的链接。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/338607.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

零食折扣店,注定昙花一现?

年终岁末&#xff0c;又到了各类休闲零食产品一年一度的销售旺季。与过去不同的是&#xff0c;近年来的休闲零食赛道正因大量零食折扣店的涌现而显得热闹非凡。 随着主打折扣、低价的零食折扣店成为消费者特别是三四线下沉市场消费者的新宠&#xff0c;资本开始涌入并快速推动…

com域名注册腾讯云价格

腾讯云com域名首年价格&#xff0c;企业新用户注册com域名首年1元&#xff0c;个人新用户注册com域名33元首年&#xff0c;非新用户注册com域名首年元85元一年&#xff0c;优惠价75元一年&#xff0c;com域名续费85元一年。腾讯云百科txybk.com分享腾讯云com域名注册优惠价格&a…

tag 标签

tag 标签 在使用 Git 版本控制的过程中&#xff0c;会产生大量的版本。如果我们想对某些重要版本进行记录&#xff0c;就可以给仓库历史中的某一个commit 打上标签&#xff0c;用于标识。 在本章中&#xff0c;我们将会学习如何列出已有的标签、如何创建和删除新的标签、以及…

找不到vcruntime140_1.dll无法继续执行怎么办?全面分析修复方法

当系统提示vcruntime140_1.dll文件出现错误时&#xff0c;可能会引发一系列影响计算机正常运行的问题。这个特定的动态链接库文件&#xff08;DLL&#xff09;是Microsoft Visual C Redistributable的一部分&#xff0c;对于许多基于Windows的应用程序来说至关重要。一旦vcrunt…

Java streamFile

1.Stream流 1.1体验Stream流【理解】 案例需求 按照下面的要求完成集合的创建和遍历 创建一个集合&#xff0c;存储多个字符串元素 把集合中所有以"张"开头的元素存储到一个新的集合 把"张"开头的集合中的长度为3的元素存储到一个新的集合 遍历上一步得…

SQL慢语句执行的很慢,如何分析优化呢,(如何优化的呢?)

慢查询出现的情况&#xff1a; SQL执行慢如何解决&#xff1f; 可以采用MySQL自带的分析工具Explain。 通过key和key_len检查是否命中了索引&#xff08;如果你已经添加了索引&#xff0c;还可以判断索引是否失效&#xff09;通过type字段查看SQL是否有进一步优化的空间&#…

php 文件操作

目录 1.file_xxx 2.fopen 1.file_xxx 文件读写的内容都是字符串数据格式 readfile(); //读取文件内容&#xff0c;并返回文件的长度 file_get_contents(文件路径); //读取文件。支持本地文件和远程文件url file_put_contents(文件路径, 内容); //写入数据&#xff0c;保存…

Halcon图像金字塔inspect_shape_model

Halcon图像金字塔 本文将讲述一种加速模板匹配的方法——图像金字塔。在Halcon的模板匹配过程中&#xff0c;除了基于描述符的匹配之外&#xff0c;其他几种匹配方法都用到了图像金字塔。图像金字塔是按照一定的排列顺序显示的一系列图像信息&#xff0c;包括原始图像和不同尺…

AI 的未来是开源的

想象一下&#xff0c;在未来&#xff0c;人工智能不会被锁在公司的金库里&#xff0c;而是由全球创新者社区一砖一瓦地在开放中构建的。协作&#xff0c;而不是竞争&#xff0c;推动进步&#xff0c;道德考虑与原始绩效同等重要。这不是科幻小说&#xff0c;而是人工智能发展核…

LeetCode---380周赛

题目列表 3005. 最大频率元素计数 3006. 找出数组中的美丽下标 I 3007. 价值和小于等于 K 的最大数字 3008. 找出数组中的美丽下标 II 一、最大频率元素计数 这题就是个简单的计数题&#xff0c;正常遍历统计数据即可&#xff0c;关键是你要会写代码逻辑。 代码如下&…

代码随想录二刷 | 二叉树 | 把二叉搜索树转换为累加树

代码随想录二刷 &#xff5c; 二叉树 &#xff5c; 把二叉搜索树转换为累加树 题目描述解题思路递归法迭代法 代码实现递归法迭代法 题目描述 538.把二叉搜索树转换为累加树 给出二叉 搜索 树的根节点&#xff0c;该树的节点值各不相同&#xff0c;请你将其转换为累加树&…

【C++干货铺】C++11新特性——右值引用、移动构造、完美转发

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 左值与左值引用 右值与右值引用 左值引用和右值引用的比较 左值引用总结&#xff1a; 右值引用总结&#xff1a; 左值引用的作用和意义 右值引用的使用场景和…

C# Socket通信从入门到精通(17)——单个异步UDP服务器监听一个客户端C#代码实现

前言: 我们在开发UDP通信程序时,除了开发UDP同步客户端程序,有时候我们也需要开发异步UDP服务器程序,所谓的异步最常见的应用就是服务器接收客户端数据以后,程序不会卡在数据接收这里,而是可以继续往下执行,这在实际项目中是经常会遇到的,所以说掌握异步UDP服务器程序…

蓝桥杯省赛无忧 编程9

#include<bits/stdc.h> using namespace std; int main() {int n,k,ans0;cin>>n>>k;while(n--){int a;cin>>a;ansa&1;}if(ans&1) cout<<"Alice"<<\n;else cout<<"Bob"; return 0; }这个游戏是基于数…

Windows主机Navicat远程连接到Ubuntu18.04虚拟机MySQL

1. 在虚拟机上安装MySQL sudo apt-get install mysql-server sudo apt-get install libmysqlclient-dev 2. 检查安装 sudo netstat -tap | grep mysql 3. 查看默认密码 sudo cat /etc/mysql/debian.cnf 4. 用查看到的密码登录MySQL server&#xff0c;修改root用户的密码 …

OpenHarmonyOS-gn与Ninja

GN语法及在鸿蒙的使用 [gnninja学习 0x01]gn和ninja是什么 ohos_sdk/doc/subsys-build-gn-coding-style-and-best-practice.md GN 语言与操作 一、gn简介 gn是generate ninja的缩写&#xff0c;它是一个元编译系统&#xff08;meta-build system&#xff09;,是ninja的前端&am…

系统架构设计师教程(十三)层次式架构设计理论与实践

层次式架构设计理论与实践 13.1 层次式体系结构概述13.2 表现层框架设计13.2.1 表现层设计模式13.2.2 使用XML设计表现层&#xff0c;统一Web Form与Windows Form的外观13.2.3表现层中UIP设计思想13.2.4 表现层动态生成设计思想 13.3 中间层架构设计13.3.1 业务逻辑层组件设计1…

C++ | 五、哈希表 Hash Table(数组、集合、映射)、迭代器

哈希表基础 哈希表是一类数据结构&#xff08;哈希表包含数组、集合和映射&#xff0c;和前两篇文章叙述的字符串、链表平级&#xff09;哈希表概念&#xff1a;类似于Python里的字典类型&#xff0c;哈希表把关键码key值通过哈希函数来和哈希表上的索引对应起来&#xff0c;之…

对testfire.net进行信息收集,采用googlehacking语法,fofa等包括子端口号、子域名,备案信息,所属资产等等

采用被动的信息收集对testfire.net进行信息收集。 使用命令查询真实IP地址: nslookup testfire.net 使用googlehacking语法: 使用子域名查询网站查询一下子域名&#xff1a; 利用fofa查询一些信息&#xff1a; 利用whois 查找备案信息等&#xff1a; 尝试绕过千锋官网的cdn 利…

国考省考行测:选词填空,逻辑填空,语境分析,语意辨析,刷题,

国考省考行测&#xff1a;选词填空&#xff0c;逻辑填空&#xff0c;语境分析 2022找工作是学历、能力和运气的超强结合体! 公务员特招重点就是专业技能&#xff0c;附带行测和申论&#xff0c;而常规国考省考最重要的还是申论和行测&#xff0c;所以大家认真准备吧&#xff0…