DBSCAN算法基本原理及C++实现

本文深入探讨了DBSCAN聚类算法的原理,并提供了一种使用C++语言的具体实现方式。通过对比分析,作者详细解释了算法的运行机制,并分享了用于验证算法准确性的Matlab代码。此外,文章还提供了完整的C++代码示例,包括数据读取、点间距离计算及聚类过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

本篇文章分为两部分:原理和C++实现

原理

参考一下blog

https://blog.youkuaiyun.com/u011557212/article/details/53203323

https://blog.youkuaiyun.com/k76853/article/details/50440182

该博客里面含C++源码,但是没有给到具体数据,而且代码第70行if语句没有加{},所以得到的结果是有问题的。但是加了{}就没问题。读者可以自己尝试。

C++实现

自己写了一个算法,思路跟上面的blog的伪代码一样。 本人还写了一个matlab的简单代码去验证自己算法的准确性。如果以下代码有错误,欢迎指出。

c++文件:

/*
DBSCAN algorithm

author:Elen Huo

Time:2019/9/19
*/
#include<iostream>
#include<vector>
#include <sstream>
#include <fstream>
using namespace std;

class point {
public:
	float x;
	float y;
	int pointtype;//1 noise 2 border 3 core
	int visited;
	int cluster;
	int pts;
	vector<point*>N; //point指针的向量
	point(){}
	point(float a, float b):x(a),y(b){
		pointtype = 1;
		visited = 0;
		cluster = 0;
		pts = 0;
	}

};

/*数据输入处理*/
float stringToFloat(string i) {
	stringstream sf;
	float score = 0;
	sf << i;
	sf >> score;
	return score;
}
/*数据输入处理*/
vector<point> openFile(const char* dataset) {  //数据返回类型 
	fstream file;
	file.open(dataset, ios::in);
	if (!file)
	{
		cout << "Open File Failed!" << endl;
		vector<point> a;
		return a;
	}
	vector<point> data;//动态数组 point类
	int i = 1;
	while (!file.eof()) {
		string temp;
		file >> temp;
		int split = temp.find(',', 0);
		point p(stringToFloat(temp.substr(0, split)), stringToFloat(temp.substr(split + 1, temp.length() - 1)));//point构造函数
		data.push_back(p);
	}
	file.close();
	cout << "successful!" << endl;
	return data;//处理得到point类数据包含x,y,cluster
}

//计算两点距离
float dis(point a, point b)
{
	return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}


//主程序
void dbscan(vector<point>dataset, float eps, int minpts)
{

	int count = 0;
	int len = dataset.size();
	cout << "len" << len << endl;
	for (int i = 0; i < len; i++)
	{
		for (int j = 0; j < len; j++)
		{
			if (i == j)continue;
			
			else if (dis(dataset[i], dataset[j]) < eps)
			{
				dataset[i].N.push_back(&dataset[j]);
			}
			
		}
	}
	
	for (int i = 0; i < len; i++)
	{
		
		if (dataset[i].visited == 1)continue;
		dataset[i].visited = 1;
		
		if (dataset[i].N.size() >= minpts) 
		{
			count++;
			dataset[i].pointtype = 3;
			dataset[i].cluster = count;
			for (int j = 0; j < dataset[i].N.size(); j++)
			{
				if (dataset[i].N[j]->visited == 1)continue;//访问dataset[j]的属性
				dataset[i].N[j]->visited = 1;   //dataset[i].N[j]->  就是dataset[j]
				if (dataset[i].N[j]->N.size() > minpts)
				{
					for (int k = 0; k < dataset[i].N[j]->N.size(); k++)
					dataset[i].N.push_back(&(*(dataset[i].N[j]->N[k]))); //传递另一个dataset向量里面的元素内的成员N里面存储其他dataset的地址值  注意得到的是地址
					dataset[i].N[j]->pointtype = 3;
				}
				else dataset[i].N[j]->pointtype = 2;
				if (dataset[i].N[j]->cluster == 0)
					dataset[i].N[j]->cluster = count;

			}
		}
	}
	cout << "output" << endl;
	//output
	fstream clustering;
	clustering.open("Elen_cluster_.txt", ios::out);
	for (int i = 0; i < len; i++) {
		if (dataset[i].pointtype == 2) //边界点
			clustering << dataset[i].x << "," << dataset[i].y << "," << dataset[i].cluster << "\n";
	}
	for (int i = 0; i < len; i++) {
		if (dataset[i].pointtype == 3) //核心点
		clustering << dataset[i].x << "," << dataset[i].y << "," << dataset[i].cluster << "\n";
	}
	clustering.close();

}
	
	




int main() {
	vector<point> dataset = openFile("dataset.txt");
	dbscan(dataset, 300, 6);
	return 0;
}

数据文件 

68.601997,102.491997
454.665985,264.808990
101.283997,169.285995
372.614990,263.140991
300.989014,46.555000
100.904999,205.776993
110.170998,55.647999
118.856003,47.445999
355.247009,76.431000
276.085999,182.048004

数据只是随便给的,所以代码里面设的半径比较大,但是对算法本身没有影响。自己可以尝试修改数据。

第一篇blog有很多不足之处,如果有错误请指出,谢谢。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值