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

 

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

原理

参考一下blog

https://blog.csdn.net/u011557212/article/details/53203323

https://blog.csdn.net/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有很多不足之处,如果有错误请指出,谢谢。

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
DBSCAN算法C++实现需要以下步骤: 1. 定义一个Point类,用于存储每个点的坐标和聚类信息。 2. 定义一个DBSCAN类,包含以下成员函数: - init函数:初始化N个坐标点。 - regionQuery函数:计算每个点的邻域内的点。 - expandCluster函数:扩展聚类。 - dbscan函数:执行DBSCAN算法。 3. 在main函数中,创建一个DBSCAN对象并调用dbscan函数进行聚类。 下面是一个简单的DBSCAN算法C++实现的代码示例: ``` #include <iostream> #include <cstdlib> #include <ctime> #include <vector> #include <cmath> using namespace std; const int N = 100; // 坐标点数量 const double eps = 1.0; // 邻域半径 const int minPts = 5; // 最小邻域点数 class Point { public: double x, y; int cluster; }; class DBSCAN { public: Point point[N]; vector<int> neighborPts[N]; void init(int n) { srand((unsigned)time(NULL)); for(int i=0; i<n; i++) { point[i].x = rand() % (N+1); point[i].y = rand() % (N+1); point[i].cluster = -1; } } void regionQuery(int p) { neighborPts[p].clear(); for(int i=0; i<N; i++) { if(i == p) continue; double dist = sqrt(pow(point[i].x - point[p].x,2) + pow(point[i].y - point[p].y, 2)); if(dist <= eps) { neighborPts[p].push_back(i); } } } void expandCluster(int p, int c) { point[p].cluster = c; for(int i=0; i<neighborPts[p].size(); i++) { int np = neighborPts[p][i]; if(point[np].cluster == -1) { point[np].cluster = c; regionQuery(np); if(neighborPts[np].size() >= minPts) { expandCluster(np, c); } } } } void dbscan() { int c = 0; for(int i=0; i<N; i++) { if(point[i].cluster != -1) continue; regionQuery(i); if(neighborPts[i].size() < minPts) { point[i].cluster = 0; // 噪声点 } else { c++; expandCluster(i, c); } } } }; int main() { DBSCAN dbscan; dbscan.init(N); dbscan.dbscan(); for(int i=0; i<N; i++) { cout << "Point " << i << ": (" << dbscan.point[i].x << ", " << dbscan.point[i].y << ") Cluster: " << dbscan.point[i].cluster << endl; } return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值