【计算几何】贝塞尔曲线 B样条曲线简介及其离散化 + Python C++ 代码实现

news2024/11/16 2:56:00

文章目录

  • 一、贝塞尔曲线
  • 二、B样条曲线
  • 三、Python 代码实现B样条曲线离散化
  • 四、C++ 代码实现B样条曲线离散化
    • 4.1 主要代码
    • 4.2 其余类
    • 4.3 离散效果展示(在CAD中展示)


本文只做简介,关于贝塞尔曲线和B样条曲线的详细介绍,请参考:详解样条曲线(上)(包含贝塞尔曲线)
部分图片来源于:https://zhuanlan.zhihu.com/p/344934774

一、贝塞尔曲线

讲之前,我们先看一张图:
在这里插入图片描述
这里的 P0、P1、P2 分别称之为控制点,贝塞尔曲线的产生完全与这三个点位置相关。

这也就意味着,我们可以通过调节控制点的位置,进而调整整个曲线。

那么,似乎最开始的控制点,也不一定是三个?如果是四个、五个,甚至更多呢?

在这里插入图片描述

如此一来,你会发现贝塞尔曲线内的递归结构。实际上,上述介绍的分别是三阶、四阶、五阶的贝塞尔曲线,贝塞尔曲线可以由阶数递归定义。

一个在线玩贝塞尔曲线的链接:在线玩贝塞尔曲线

下面直接给贝塞尔曲线的通用公式

假设一共有 n + 1 \mathrm{n}+1 n+1 个点 P 0 , P 1 , ⋯   , P n \mathrm{P}_0, \mathrm{P}_1, \cdots, \mathrm{P}_{\mathrm{n}} P0,P1,,Pn ,这 n + 1 \mathrm{n}+1 n+1 个点确定了 n \mathrm{n} n 次的贝塞尔曲线。
n n n 阶贝塞尔曲线 B n ( t ) B^n(t) Bn(t) 可以由前 n n n 个点决定的 n − 1 n-1 n1 次贝塞尔曲线 B n − 1 ( t ∣ P 0 , ⋯   , P n − 1 ) B^{n-1}\left(t \mid P_0, \cdots, P_{n-1}\right) Bn1(tP0,,Pn1) 与后 n n n 个点决定的 n − 1 n-1 n1 次贝塞尔曲线 B n − 1 ( t ∣ P 1 , ⋯   , P n ) \mathrm{B}^{\mathrm{n}-1}\left(\mathrm{t} \mid \mathrm{P}_1, \cdots, \mathrm{P}_{\mathrm{n}}\right) Bn1(tP1,,Pn) 线性组合递推而来,即
B n ( t ∣ P 0 , P 1 , ⋯   , P n ) = ( 1 − t ) B n − 1 ( t ∣ P 0 , P 1 , ⋯   , P n − 1 ) + t B n − 1 ( t ∣ P 1 , P 2 , ⋯   , P n ) \mathrm{B}^{\mathrm{n}}\left(\mathrm{t} \mid \mathrm{P}_0, \mathrm{P}_1, \cdots, \mathrm{P}_{\mathrm{n}}\right)=(1-\mathrm{t}) \mathrm{B}^{\mathrm{n}-1}\left(\mathrm{t} \mid \mathrm{P}_0, \mathrm{P}_1, \cdots, \mathrm{P}_{\mathrm{n}-1}\right)+\mathrm{t} \mathrm{B}^{\mathrm{n}-1}\left(\mathrm{t} \mid \mathrm{P}_1, \mathrm{P}_2, \cdots, \mathrm{P}_{\mathrm{n}}\right) Bn(tP0,P1,,Pn)=(1t)Bn1(tP0,P1,,Pn1)+tBn1(tP1,P2,,Pn)
且一次贝塞尔曲线,即为由两点决定的线段,也即
B 1 ( t ∣ P 0 , P 1 ) = ( 1 − t ) P 0 + t P 1 \mathrm{B}^1\left(\mathrm{t} \mid \mathrm{P}_0, \mathrm{P}_1\right)=(1-\mathrm{t}) \mathrm{P}_0+\mathrm{tP}_1 B1(tP0,P1)=(1t)P0+tP1
可以得到 n \mathrm{n} n 次贝塞尔曲线的表达通式为
B ( t ) = ∑ i = 0 n C n i ( 1 − t ) n − i t i P i B(t)=\sum_{i=0}^n C_n^i(1-t)^{n-i} t^i P_i B(t)=i=0nCni(1t)nitiPi

有了通用公式,我们就可以通过遍历t来离散化贝塞尔曲线了!

二、B样条曲线

几个概念

  • 控制点: 也就是控制曲线的点,等价于贝塞尔函数的控制点,通过控制点可以控制曲线形状。假设有 n + 1 n+1 n+1 个控制点 P 0 , P 1 , P 2 , ⋯   , P n \mathrm{P}_0, \mathrm{P}_1, \mathrm{P}_2, \cdots, \mathrm{P}_{\mathrm{n}} P0,P1,P2,,Pn
  • 节点: 这个跟控制点没有关系,而是人为地将目标曲线分为若干个部分,其目的就是尽量使得各个部分有所影响但也有一定独立性, 这也是为什么B样条中,有时一个控制点的改变,不会很大影响到整条曲线,而只影响到局部的原因,这是区别于贝塞尔曲线的一 点。节点划分影响到权重计算,可以预想到的是,实现局部性的影响的原理应该是在生成某区间内的点时,某些控制点前的权重值会 为 0 ,即对该点没有贡献,所以才有上述特点。事实上,就是如此的。先了解有这个概念即可。假设我们划分了 m + 1 m+1 m+1 个节点 t 0 , t 1 , ⋯   , t m \mathrm{t}_0, \mathrm{t}_1, \cdots, \mathrm{t}_{\mathrm{m}} t0,t1,,tm ,将曲线分成了 m \mathrm{m} m
  • 次与阶:次的概念就是贝塞尔中次的概念,即权重中 t t t 的最高幂次。而 阶=次 +1 。这里只需要知道次这个概念即可。假设我们用 k k k 表示次,即 k \mathrm{k} k 次。

B 样条曲线比贝塞尔曲线的设计要复杂许多,我们直接通过他们的公式大致比较一下贝塞尔曲线与 B 样条曲线的区别:

贝塞尔曲线

B ( t ) = ∑ i = 0 n C n i ( 1 − t ) n − i t i P i , t ∈ [ 0 , 1 ] B(t)=\sum_{i=0}^n C_n^i(1-t)^{n-i} t^i P_i, \quad t \in[0,1] B(t)=i=0nCni(1t)nitiPi,t[0,1]

B样条曲线

对于 n + 1 n+1 n+1 个控制点 P 0 , P 1 , ⋯   , P n P_0, P_1, \cdots, P_n P0,P1,,Pn ,有一个包含 m + 1 m+1 m+1 个节点的列表 (或节点向量) t 0 , t 1 , ⋯   , t m t_0, t_1, \cdots, t_m t0,t1,,tm ,其 k k k B B B 样条曲线表达式为 (且 m = n + k + 1 ) m=n+k+1) m=n+k+1)

P ( t ) = ∑ i = 0 n B i , k ( t ) P i \mathrm{P}(\mathrm{t})=\sum_{\mathrm{i}=0}^{\mathrm{n}} \mathrm{B}_{\mathrm{i}, \mathrm{k}}(\mathrm{t}) \mathrm{P}_{\mathrm{i}} P(t)=i=0nBi,k(t)Pi

可以发现,B样条曲线的核心就是 B i , k ( t ) \mathrm{B}_{\mathrm{i}, \mathrm{k}}(\mathrm{t}) Bi,k(t) ,它被称为 k 次 B 样条基函数,也叫调和函数。

它满足如下递推式(deBoor递推式):

k = 0 ,   B i , 0 ( t ) = { 1 , t ∈ [ t i , t i + 1 ] 0 ,  Otherwise  k > 0 ,   B i , k ( t ) = t − t i t i + k − t i B i , k − 1 ( t ) + t i + k + 1 − t t i + k + 1 − t i + 1   B i + 1 , k − 1 ( t ) \begin{gathered} \mathrm{k}=0, \quad \mathrm{~B}_{\mathrm{i}, 0}(\mathrm{t})= \begin{cases}1, & \mathrm{t} \in\left[\mathrm{t}_{\mathrm{i}}, \mathrm{t}_{\mathrm{i}}+1\right] \\ 0, & \text { Otherwise }\end{cases} \\ \mathrm{k}>0, \quad \mathrm{~B}_{\mathrm{i}, \mathrm{k}}(\mathrm{t})=\frac{\mathrm{t}-\mathrm{t}_{\mathrm{i}}}{\mathrm{t}_{\mathrm{i}+\mathrm{k}}-\mathrm{t}_{\mathrm{i}}} \mathrm{B}_{\mathrm{i}, \mathrm{k}-1}(\mathrm{t})+\frac{\mathrm{t}_{\mathrm{i}+\mathrm{k}+1}-\mathrm{t}}{\mathrm{t}_{\mathrm{i}+\mathrm{k}+1}-\mathrm{t}_{\mathrm{i}+1}} \mathrm{~B}_{\mathrm{i}+1, \mathrm{k}-1}(\mathrm{t}) \end{gathered} k=0, Bi,0(t)={1,0,t[ti,ti+1] Otherwise k>0, Bi,k(t)=ti+ktittiBi,k1(t)+ti+k+1ti+1ti+k+1t Bi+1,k1(t)

三、Python 代码实现B样条曲线离散化

import time

import numpy as np
from matplotlib import pyplot as plt


def getB(i, k, t, T, B):
    '''
    获取B[i][k]的值
    :param i: B样条基函数矩阵行索引
    :param k: 当前阶数(B样条基函数矩阵列索引)
    :param t: 当前t值
    :param T: 节点值列表
    :param B: B样条基函数矩阵
    :return: B[i][k]的值
    '''
    if B[i, k] < 0:
        if k == 0:
            if T[i] <= t <= T[i + 1]:
                B[i, k] = 1
            else:
                B[i, k] = 0
        else:
            w1 = w2 = 0
            if T[i + k] - T[i] != 0:
                w1 = (t - T[i]) / (T[i + k] - T[i])
            if T[i + k + 1] - T[i + 1] != 0:
                w2 = (T[i + k + 1] - t) / (T[i + k + 1] - T[i + 1])
            B[i, k] = w1 * getB(i, k - 1, t, T, B) + w2 * getB(i + 1, k - 1, t, T, B)
    return B[i][k]


def plot_spline(P, K, T):
    '''
    根据P、K、T绘制离散化的B样条曲线及其控制点
    :param P: 控制点列表
    :param K: B样条曲线阶数
    :param T: 节点值列表
    :return: None
    '''
    startTime = time.time()
    t = min(T)
    step = T[-1] / 100
    X, Y = [], []
    while t <= max(T):
        B = np.zeros((len(T) - 1, K + 1))
        B.fill(-1)
        x = y = 0
        for i in range(len(P)):
            b = getB(i, K, t, T, B)
            x += b * P[i][0]
            y += b * P[i][1]
        X.append(x)
        Y.append(y)
        t += step
    print("用时:", (time.time() - startTime), "s")
    plt.plot(X, Y, marker='o', label="fit point")
    plt.scatter([p[0] for p in P], [p[1] for p in P], color="red", label="control point")
    plt.legend()
    plt.show()


if __name__ == '__main__':
    '''
    P: 控制点列表
    T: 节点值列表
    K: B样条曲线阶数
    '''

    # 测试案例1
    P = [[50, 50], [100, 300], [300, 100], [380, 200], [400, 600]]
    T = [0, 0, 0, 4 / 9, 5 / 9, 1, 1, 1]
    K = 2
    plot_spline(P, K, T)

    # 测试案例2
    P = [[2982.51, 9384.89], [3478.42, 4212.45], [9353.02, 6690.64], [4635.54, 1810.51], [12951.5, 5940.83],
         [7458.4, 10299.9], [14973.3, 7948.8], [8780.82, 11392.9], [14792.3, 10948.1]]
    T = [0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 6, 6, 6]
    K = 3
    plot_spline(P, K, T)

控制台输出

用时: 0.001992940902709961 s
用时: 0.003986835479736328 s

结果展示

在这里插入图片描述
在这里插入图片描述

四、C++ 代码实现B样条曲线离散化

4.1 主要代码

// 递归填B表
double getBValue(int i, int k, double t, vector<double> kVector, vector<vector<double>> B){
	if (B[i][k] == NULL){
		if (k == 0){
			if (kVector[i] <= t && kVector[i + 1] >= t){
				B[i][k] = 1;
			}
			else{
				B[i][k] = 0;
			}
		}
		else{
			double w1 = 0;
			double w2 = 0;
			if (kVector[i + k] - kVector[i] != 0){
				w1 = (t - kVector[i]) / (kVector[i + k] - kVector[i]);
			}
			if (kVector[i + k + 1] - kVector[i + 1] != 0){
				w2 = (kVector[i + k + 1] - t) / (kVector[i + k + 1] - kVector[i + 1]);
			}
			B[i][k] = w1 * getBValue(i, k - 1, t, kVector, B) + w2 * getBValue(i + 1, k - 1, t, kVector, B);
		}
	}
	return B[i][k];
}

// B样条曲线离散化
DXFPolyLineEntities splineDiscretization(DXFSpline spline){
	DXFPolyLineEntities poly = DXFPolyLineEntities();
	int K = spline.degree;
	// 获取kVector
	vector<double> kVector(spline.kVector.size());
	for (int i = 0; i < spline.kVector.size(); i++){
		kVector[i] = spline.kVector[i].k;
	}
	// 根据函数获得离散点
	for (double t = kVector[0]; t <= kVector[spline.nKnots - 1]; t += (kVector[spline.nKnots - 1] / SPLINE_D)){
		double x = 0.0;
		double y = 0.0;
		// 初始化B表
		vector<vector<double>> B(spline.nKnots - 1, vector<double>(K + 1,NULL));
		// 遍历控制点集合
		for (int i = 0; i < spline.controlPointVector.size(); i++){
			// 已知 i,K,t, 推出B值
			double bValue = getBValue(i, K, t, kVector, B);
			x += (bValue * spline.controlPointVector[i].x);
			y += (bValue * spline.controlPointVector[i].y);
		}
		poly.vertex.push_back(DL_VertexData(x, y));
	}
	return poly;
}

4.2 其余类

//多段线实体对象
class DXFPolyLineEntities
{
public:
	vector<DL_VertexData> vertex;//顶点
	bool isclose;//闭合标志位
};
/**
 * Vertex Data.
 */
struct DXFLIB_EXPORT DL_VertexData {
    /**
     * Constructor.
     * Parameters: see member variables.
     */
    DL_VertexData(double px=0.0, double py=0.0, double pz=0.0,
                  double pBulge=0.0) {
        x = px;
        y = py;
        z = pz;
        bulge = pBulge;
    }

    /*! X Coordinate of the vertex. */
    double x;
    /*! Y Coordinate of the vertex. */
    double y;
    /*! Z Coordinate of the vertex. */
    double z;
    /*! Bulge of vertex.
     * (The tangent of 1/4 of the arc angle or 0 for lines) */
    double bulge;
};
// 样条曲线对象
class DXFSpline
{
public:
	// 样条曲线的阶数
	int degree;
	// 节点数
	int nKnots;
	// 控制点数
	int nControl;
	// 拟合点数(如果有)
	int nFit;
	// 样条曲线标志(按位编码)
	// 1 = 闭合样条曲线;
	// 2 = 周期样条曲线;
	// 4 = 有理样条曲线;
	// 8 = 平面;
	// 16 = 线性(同时设置平面位)
	int flags;

	// 相切开始和结束点坐标
	double tangentStartX;
	double tangentStartY;
	double tangentStartZ;
	double tangentEndX;
	double tangentEndY;
	double tangentEndZ;

	// 控制点集合
	vector<DL_ControlPointData> controlPointVector;
	// 拟合点集合
	vector<DL_FitPointData> fitPointVector;
	// 节点值集合
	vector<DL_KnotData> kVector;
};
/**
* Spline control point data.
*/
struct DXFLIB_EXPORT DL_ControlPointData {
	/**
	* Constructor.
	* Parameters: see member variables.
	*/
	DL_ControlPointData(){}
	DL_ControlPointData(double px, double py, double pz, double weight) {
		x = px;
		y = py;
		z = pz;
		w = weight;
	}

	/*! X coordinate of the control point. */
	double x;
	/*! Y coordinate of the control point. */
	double y;
	/*! Z coordinate of the control point. */
	double z;
	/*! Weight of control point. */
	double w;
};
/**
* Spline fit point data.
*/
struct DXFLIB_EXPORT DL_FitPointData {
	/**
	* Constructor.
	* Parameters: see member variables.
	*/
	DL_FitPointData(){}
	DL_FitPointData(double x, double y, double z) : x(x), y(y), z(z) {}

	/*! X coordinate of the fit point. */
	double x;
	/*! Y coordinate of the fit point. */
	double y;
	/*! Z coordinate of the fit point. */
	double z;
};
/**
* Spline knot data.
*/
struct DXFLIB_EXPORT DL_KnotData {
	/**
	* Constructor.
	* Parameters: see member variables.
	*/
	DL_KnotData() {}
	DL_KnotData(double pk) {
		k = pk;
	}

	/*! Knot value. */
	double k;
};

4.3 离散效果展示(在CAD中展示)

案例1

在这里插入图片描述

在这里插入图片描述

案例2

在这里插入图片描述

在这里插入图片描述

案例3

在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

unity UGUI系统梳理 - 基本布局

偷懒了&#xff0c;部分节选unity API API 1、矩形工具 为了便于布局&#xff0c;每个 UI 元素都表示为矩形。可使用工具栏中的__矩形工具 (Rect Tool)__ 在 Scene 视图中操纵此矩形。矩形工具既可用于 Unity 的 2D 功能&#xff0c;也可用于 UI&#xff0c;实际上甚至还可用…

C/C++开发,无可避免的多线程(篇三).协程及其支持库

一、c20的协程概念 在c20标准后&#xff0c;在一些函数中看到co_await、co_yield、co_return这些关键词&#xff0c;这是c20为协程实现设计的运算符。 协程是能暂停执行以在之后恢复的函数。原来我们调用一个功能函数时&#xff0c;只要调用了以后&#xff0c;就要完整执行完该…

【Kettle-佛系总结】

Kettle-佛系总结Kettle-佛系总结1.kettle介绍2.kettle安装3.kettle目录介绍4.kettle核心概念1.转换2.步骤3.跳&#xff08;Hop&#xff09;4.元数据5.数据类型6.并行7.作业5.kettle转换1.输入控件1.csv文件输入2.文本文件输入3.Excel输入4.XML输入5.JSON输入6.表输入2.输出控件…

百度Apollo规划算法——轨迹拼接

百度Apollo规划算法——轨迹拼接引言轨迹拼接1、什么是轨迹拼接&#xff1f;2、为什么要进行轨迹拼接&#xff1f;3、结合Apollo代码为例理解轨迹拼接的细节。参考引言 在apollo的规划算法中&#xff0c;在每一帧规划开始时会调用一个轨迹拼接函数&#xff0c;返回一段拼接轨迹…

Kubernetes之服务发布

学了服务发现后&#xff0c;svc的IP只能被集群内部主机及pod才可以访问&#xff0c;要想集群外的主机也可以访问svc&#xff0c;就需要利用到服务发布。 NodePort Nodeport服务是外部访问服务的最基本方式。当我们创建一个服务的时候&#xff0c;把服务的端口映射到kubernete…

【大数据AI人工智能】常见的归一化函数有哪些?分别用数学公式详细介绍

常见的归一化函数有哪些?分别用数学公式详细介绍一下。 常见的归一化函数 常见的归一化函数包括: Min-Max 归一化Z-Score 归一化Log 归一化Sigmoid 归一化下面分别介绍这些归一化函数以及它们的数学公式。 1. Min-Max 归一化 Min-Max 归一化是将原始数据线性映射到 [0,1]…

dp模型——状态机模型C++详解

状态机定义状态机顾名思义跟状态有关系&#xff0c;但到底有什么关系呢。在实际解决的时候&#xff0c;通常把状态想成节点&#xff0c;状态的转换想成有向边的有向图&#xff0c;我们来举个例子。相信大家都玩过类似枪战的游戏&#xff08;没玩过的也听说过吧&#xff09;&…

4.创建和加入通道相关(network.sh脚本createChannel函数分析)[fabric2.2]

fabric的test-network例子有一个orderer组织、两个peer组织、每个组织一个节点&#xff0c;只有系统通道&#xff08;system-channel&#xff09;&#xff0c;没有其他应用通道。我们可以使用./network.sh createChannel命令来创建一个名为mychannel的应用通道。 一、主要概念 …

【Java开发】JUC进阶 04:线程池详解

1 线程池介绍由于频繁创建销毁线程要调用native方法比较消耗资源&#xff0c;为了保证内核的充分利用&#xff0c;所以引入了线程池的概念。&#x1f4cc; 线程池优点降低资源消耗提高响应速度方便管理&#x1f4cc; 创建线程池使用Executors创建使用ThreadPoolExecutor创建&am…

Git图解-为啥是Git?怎么装?

目录 零、学习目标 一、版本控制 1.1 团队开发问题 1.2 版本控制思想 1.2.1 版本工具 二、Git简介 2.1 简介 2.2 Git环境的搭建 三、转视频版 零、学习目标 掌握git的工作流程 熟悉git安装使用 掌握git的基本使用 掌握分支管理 掌握IDEA操作git 掌握使用git远程仓…

【教程】记录Typecho Joe主题升级与Joe魔改版

目录 升级Joe 其他魔改版 Joe主题挺好看的&#xff0c;很早之前我就装了。后来官方升级了主题&#xff0c;但没有给升级教程。这里记录一下我的升级过程&#xff0c;供大家参考。 Joe Github&#xff1a;GitHub - HaoOuBa/Joe: A Theme of Typecho 升级站点&#xff1a;小锋学…

WSL2使用Nvidia-Docker实现CUDA版本自由切换

众所周知&#xff0c;深度学习的环境往往非常麻烦&#xff0c;经常不同的项目所依赖的 torch、tensorflow 包对 CUDA 的版本也有不同的要求&#xff0c;Linux 下进行 CUDA 的管理比较麻烦&#xff0c;是一个比较头疼的问题。 随着 WSL2 对物理机显卡的支持&#xff0c;Nvidia-…

用二极管和电容过滤电源波动,实现简单的稳压 - 小水泵升压改装方案

简而言之&#xff0c;就是类似采样保持电路&#xff0c;当电源电压因为电机启动而骤降时&#xff0c;用二极管避免电容电压跟着降低&#xff0c;从而让电容上连接的低功耗芯片有一个比较稳定的供电电压。没什么特别的用处&#xff0c;省个LDO 吧&#xff0c;电压跌幅太大的时候…

最详细Sql语句优化大汇总 面试必问 含解释

欢迎补充和纠正&#xff01;&#xff01;&#xff01; 目录 欢迎补充和纠正&#xff01;&#xff01;&#xff01; 基础知识 相关索引的创建 一条sql语句的执行过程 sql语句关键字的执行顺序 SQL优化 使用explain来分析Sql语句 尽量用varchar代替char 使用数值代替字符…

Vector - CAPL - 定时器函数和使用

定时器在C语言中的使用我想学习过C编程的都不会陌生&#xff0c;它能够提供延时&#xff0c;完成等待一定的时间&#xff1b;它也可以实现多线程的操作&#xff0c;并行实行某些软件功能。那在CAPL中&#xff0c;定时器又能做哪些工作呢&#xff1f;又是怎么使用的呢&#xff1…

SPringCloud:Nacos快速入门及相关属性配置

目录 一、Nacos快速入门 1、在父工程中添加spring-cloud-alilbaba的管理依赖 2、如果有使用eureka依赖&#xff0c;将其注释 3、添加nacos的客户端依赖 4、修改yml文件&#xff0c;注释eureka配置 5、启动测试 二、Nacos相关属性配置 1、Nacos服务分级存储 2、根据集群…

ELasticsearch基本使用——基础篇

1.初识elasticsearch1.1.了解ES1.1.1.elasticsearch的作用elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容例如&#xff1a;在GitHub搜索代码在电商网站搜索商品在谷歌搜索答案在打车软件搜索…

Oracle中merge Into的用法

Oracle中merge Into的用法 使用场景 在操作数据库时&#xff0c;数据存在的情况下&#xff0c;进行update操作&#xff1b;不存在的情况下&#xff0c;进行insert操作&#xff1b;在Oracle数据库中&#xff0c;能够使用merge into来实现。 基本语法 merge into table_name …

Go项目的目录结构基本布局

前言 随着项目的代码量在不断地增长&#xff0c;不同的开发人员按自己意愿随意布局和创建目录结构&#xff0c;项目维护性就很差&#xff0c;代码也非常凌乱。良好的目录与文件结构十分重要&#xff0c;尤其是团队合作的时候&#xff0c;良好的目录与文件结构可以减少很多不必要…

HashSet原理

HashSet原理HashSet原理1.概述2.底层代码3.原理图解4.总结4.1: 1.7原理总结4.2: 1.8原理总结HashSet原理 1.概述 ​ HashSet 实现 Set 接口&#xff0c;由哈希表&#xff08;实际上是一个 HashMap 实例&#xff09;支持。它不保证 set 的 迭代顺序&#xff1b;特别是它不保证…