dbscan算法c语言实现,用C++实现DBSCAN聚类算法

这几天由于工作需要,对DBSCAN聚类算法进行了C++的实现。时间复杂度O(n^2),主要花在算每个点领域内的点上。算法很简单,现共享大家参考,也希望有更多交流。

数据点类型描述如下:

复制代码 代码如下:

#include

using namespace std;

const int DIME_NUM=2;        //数据维度为2,全局常量

//数据点类型

class DataPoint

{

private:

unsigned long dpID;                //数据点ID

double dimension[DIME_NUM];        //维度数据

long clusterId;                    //所属聚类ID

bool isKey;                        //是否核心对象

bool visited;                    //是否已访问

vector arrivalPoints;    //领域数据点id列表

public:

DataPoint();                                                    //默认构造函数

DataPoint(unsigned long dpID,double* dimension , bool isKey);    //构造函数

unsigned long GetDpId();                //GetDpId方法

void SetDpId(unsigned long dpID);        //SetDpId方法

double* GetDimension();                    //GetDimension方法

void SetDimension(double* dimension);    //SetDimension方法

bool IsKey();                            //GetIsKey方法

void SetKey(bool isKey);                //SetKey方法

bool isVisited();                        //GetIsVisited方法

void SetVisited(bool visited);            //SetIsVisited方法

long GetClusterId();                    //GetClusterId方法

void SetClusterId(long classId);        //SetClusterId方法

vector& GetArrivalPoints();    //GetArrivalPoints方法

};

这是实现:

复制代码 代码如下:

#include "DataPoint.h"

//默认构造函数

DataPoint::DataPoint()

{

}

//构造函数

DataPoint::DataPoint(unsigned long dpID,double* dimension , bool isKey):isKey(isKey),dpID(dpID)

{

//传递每维的维度数据

for(int i=0; i

{

this->dimension[i]=dimension[i];

}

}

//设置维度数据

void DataPoint::SetDimension(double* dimension)

{

for(int i=0; i

{

this->dimension[i]=dimension[i];

}

}

//获取维度数据

double* DataPoint::GetDimension()

{

return this->dimension;

}

//获取是否为核心对象

bool DataPoint::IsKey()

{

return this->isKey;

}

//设置核心对象标志

void DataPoint::SetKey(bool isKey)

{

this->isKey = isKey;

}

//获取DpId方法

unsigned long DataPoint::GetDpId()

{

return this->dpID;

}

//设置DpId方法

void DataPoint::SetDpId(unsigned long dpID)

{

this->dpID = dpID;

}

//GetIsVisited方法

bool DataPoint::isVisited()

{

return this->visited;

}

//SetIsVisited方法

void DataPoint::SetVisited( bool visited )

{

this->visited = visited;

}

//GetClusterId方法

long DataPoint::GetClusterId()

{

return this->clusterId;

}

//GetClusterId方法

void DataPoint::SetClusterId( long clusterId )

{

this->clusterId = clusterId;

}

//GetArrivalPoints方法

vector& DataPoint::GetArrivalPoints()

{

return arrivalPoints;

}

DBSCAN算法类型描述:

复制代码 代码如下:

#include

#include

using namespace std;

//聚类分析类型

class ClusterAnalysis

{

private:

vector dadaSets;        //数据集合

unsigned int dimNum;            //维度

double radius;                    //半径

unsigned int dataNum;            //数据数量

unsigned int minPTs;            //邻域最小数据个数

double GetDistance(DataPoint& dp1, DataPoint& dp2);                    //距离函数

void SetArrivalPoints(DataPoint& dp);                                //设置数据点的领域点列表

void KeyPointCluster( unsigned long i, unsigned long clusterId );    //对数据点领域内的点执行聚类操作

public:

ClusterAnalysis(){}                    //默认构造函数

bool Init(char* fileName, double radius, int minPTs);    //初始化操作

bool DoDBSCANRecursive();            //DBSCAN递归算法

bool WriteToFile(char* fileName);    //将聚类结果写入文件

};

聚类实现:

复制代码 代码如下:

#include "ClusterAnalysis.h"

#include

#include

#include

/*

函数:聚类初始化操作

说明:将数据文件名,半径,领域最小数据个数信息写入聚类算法类,读取文件,把数据信息读入写进算法类数据集合中

参数:

char* fileName;    //文件名

double radius;    //半径

int minPTs;        //领域最小数据个数

返回值: true;    */

bool ClusterAnalysis::Init(char* fileName, double radius, int minPTs)

{

this->radius = radius;        //设置半径

this->minPTs = minPTs;        //设置领域最小数据个数

this->dimNum = DIME_NUM;    //设置数据维度

ifstream ifs(fileName);        //打开文件

if (! ifs.is_open())                //若文件已经被打开,报错误信息

{

cout << "Error opening file";    //输出错误信息

exit (-1);                        //程序退出

}

unsigned long i=0;            //数据个数统计

while (! ifs.eof() )                //从文件中读取POI信息,将POI信息写入POI列表中

{

DataPoint tempDP;                //临时数据点对象

double tempDimData[DIME_NUM];    //临时数据点维度信息

for(int j=0; j

{

ifs>>tempDimData[j];

}

tempDP.SetDimension(tempDimData);    //将维度信息存入数据点对象内

//char date[20]="";

//char time[20]="";

double type;    //无用信息

//ifs >> date;

//ifs >> time;    //无用信息读入

tempDP.SetDpId(i);                    //将数据点对象ID设置为i

tempDP.SetVisited(false);            //数据点对象isVisited设置为false

tempDP.SetClusterId(-1);            //设置默认簇ID为-1

dadaSets.push_back(tempDP);            //将对象压入数据集合容器

i++;        //计数+1

}

ifs.close();        //关闭文件流

dataNum =i;            //设置数据对象集合大小为i

for(unsigned long i=0; i

{

SetArrivalPoints(dadaSets[i]);            //计算数据点领域内对象

}

return true;    //返回

}

/*

函数:将已经过聚类算法处理的数据集合写回文件

说明:将已经过聚类结果写回文件

参数:

char* fileName;    //要写入的文件名

返回值: true    */

bool ClusterAnalysis::WriteToFile(char* fileName )

{

ofstream of1(fileName);                                //初始化文件输出流

for(unsigned long i=0; i

{

for(int d=0; d

of1<

of1 << dadaSets[i].GetClusterId() <

}

of1.close();    //关闭输出文件流

return true;    //返回

}

/*

函数:设置数据点的领域点列表

说明:设置数据点的领域点列表

参数:

返回值: true;    */

void ClusterAnalysis::SetArrivalPoints(DataPoint& dp)

{

for(unsigned long i=0; i

{

double distance =GetDistance(dadaSets[i], dp);    //获取与特定点之间的距离

if(distance <= radius && i!=dp.GetDpId())        //若距离小于半径,并且特定点的id与dp的id不同执行

dp.GetArrivalPoints().push_back(i);            //将特定点id压力dp的领域列表中

}

if(dp.GetArrivalPoints().size() >= minPTs)            //若dp领域内数据点数据量> minPTs执行

{

dp.SetKey(true);    //将dp核心对象标志位设为true

return;                //返回

}

dp.SetKey(false);    //若非核心对象,则将dp核心对象标志位设为false

}

/*

函数:执行聚类操作

说明:执行聚类操作

参数:

返回值: true;    */

bool ClusterAnalysis::DoDBSCANRecursive()

{

unsigned long clusterId=0;                        //聚类id计数,初始化为0

for(unsigned long i=0; i

{

DataPoint& dp=dadaSets[i];                    //取到第i个数据点对象

if(!dp.isVisited() && dp.IsKey())            //若对象没被访问过,并且是核心对象执行

{

dp.SetClusterId(clusterId);                //设置该对象所属簇ID为clusterId

dp.SetVisited(true);                    //设置该对象已被访问过

KeyPointCluster(i,clusterId);            //对该对象领域内点进行聚类

clusterId++;                            //clusterId自增1

}

//cout << "孤立点\T" << i << endl;

}

cout <

return true;    //返回

}

/*

函数:对数据点领域内的点执行聚类操作

说明:采用递归的方法,深度优先聚类数据

参数:

unsigned long dpID;            //数据点id

unsigned long clusterId;    //数据点所属簇id

返回值: void;    */

void ClusterAnalysis::KeyPointCluster(unsigned long dpID, unsigned long clusterId )

{

DataPoint& srcDp = dadaSets[dpID];        //获取数据点对象

if(!srcDp.IsKey())    return;

vector& arrvalPoints = srcDp.GetArrivalPoints();        //获取对象领域内点ID列表

for(unsigned long i=0; i

{

DataPoint& desDp = dadaSets[arrvalPoints[i]];    //获取领域内点数据点

if(!desDp.isVisited())                            //若该对象没有被访问过执行

{

//cout << "数据点\t"<< desDp.GetDpId()<

desDp.SetClusterId(clusterId);        //设置该对象所属簇的ID为clusterId,即将该对象吸入簇中

desDp.SetVisited(true);                //设置该对象已被访问

if(desDp.IsKey())                    //若该对象是核心对象

{

KeyPointCluster(desDp.GetDpId(),clusterId);    //递归地对该领域点数据的领域内的点执行聚类操作,采用深度优先方法

}

}

}

}

//两数据点之间距离

/*

函数:获取两数据点之间距离

说明:获取两数据点之间的欧式距离

参数:

DataPoint& dp1;        //数据点1

DataPoint& dp2;        //数据点2

返回值: double;    //两点之间的距离        */

double ClusterAnalysis::GetDistance(DataPoint& dp1, DataPoint& dp2)

{

double distance =0;        //初始化距离为0

for(int i=0; i

{

distance += pow(dp1.GetDimension()[i] - dp2.GetDimension()[i],2);    //距离+每一维差的平方

}

return pow(distance,0.5);        //开方并返回距离

}

算法调用就简单了:

复制代码 代码如下:

#include "ClusterAnalysis.h"

#include

using namespace std;

int main()

{

ClusterAnalysis myClusterAnalysis;                        //聚类算法对象声明

myClusterAnalysis.Init("D:\\1108\\XY.txt",500,9);        //算法初始化操作,指定半径为15,领域内最小数据点个数为3,(在程序中已指定数据维度为2)

myClusterAnalysis.DoDBSCANRecursive();                    //执行聚类算法

myClusterAnalysis.WriteToFile("D:\\1108\\XYResult.txt");//写执行后的结果写入文件

system("pause");    //显示结果

return 0;            //返回

}

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

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

相关文章

小世界网络模型代码 c 语言,新的小世界网络模型实现文本特征的提取方法与流程...

本发明涉及语义网络技术领域&#xff0c;具体涉及新的小世界网络模型实现文本特征的提取方法。背景技术&#xff1a;目前常用的文本特征提取方法&#xff0c;包括词频-反文档频率方法—TF-IDF、信息增益方法、互信息等方法&#xff1b;TF-IDF的简单结构并不能有效地反映词汇或短…

米4用linux刷机救转,小米4变砖之后如何刷机自救?大神教你小米4线刷救砖方法...

三&#xff1a;使用miflash工具刷机的步骤本工具适用于小米&#xff0c;华为&#xff0c;联想等手机品牌高通版本&#xff0c;不只是小米专用&#xff0c;教程仅供参考&#xff0c;看完一遍后再刷机。第一步&#xff1a;刷机工具安装1.下载小米手机刷机工具MiPhone2015731&…

android动态更新配置文件,Android如何动态修改Manifest文件

修改manifest文件Android Manifest.xml&#xff0c;添加相应的声明。在这里&#xff0c;我们需要将新定义的活动PrefsActivity注册到manifest文件。同前面一样&#xff0c;在Eclipse中打开AndroidManifest.xml文件会默认进入Eclipse提供的图形化编辑界面。单击Application选项卡…

com.android.phone已停止运行怎么解决方法,com.android.phone已停止运行怎么解决

在安卓手机上&#xff0c;不少用户都会遇过com.android.phone已停止的弹窗&#xff0c;尤其经常刷机的最明显。导致的原因实在太多&#xff0c;有刷机步骤不对的&#xff0c;乱改系统文件的&#xff0c;这里小编综合网上的情况以及自身经历&#xff0c;给广大安卓用户一个com.a…

android动画放大后缩小,Android 补间动画 scale(缩放)

今天又遇到了关于Android 动画方面的问题&#xff0c;免不了一番疯狂找资料&#xff0c;所幸解决了自己的问题&#xff0c;为了避免以后遇到同样的问题&#xff0c;再次到处找资料&#xff0c;于是决定写篇随笔记录下来&#xff0c;方便自己方便大家^_^&#xff1b;废话就不说了…

android 生成泛型对象,java android解析多层含有泛型对象的json数据获取不到泛型类型解析失败解决办法...

####问题描述* java 解析多层含有泛型对象的json数据获取不到泛型类型* 如果将泛型改成实际的类型就能正常解析* 如果不改成实际的类型泛型数据被解析成com.google.gson.internal.LinkedTreeMap* 如果强制转换报错:java.lang.ClassCastException: com.google.gson.internal.Lin…

android 机器人动画,Android 5.X与Android4.X版本机器人动画的区别以及制作动画的方法...

今天翻了下墙&#xff0c;解决了一直以来的疑惑问题&#xff1a;为什么Android5.0以及6.0的recovery版本&#xff0c;机器人动画怎么就只有一张图片&#xff1f;这个问题&#xff0c;我百思不得其解&#xff0c;看了很多网文&#xff0c;也只是有了个概念。请参考以下文档&…

android盒子smb,普通安卓盒子smb方法 - 怀旧游戏长廊 - A9VG电玩部落论坛 - Powered by Discuz!...

本帖最后由 slime525 于 2018-10-20 21:00 编辑1安卓下安装盒子伴侣一键自动安装Optware2win下安装Putty&#xff0c;记下盒子ip端口&#xff0c;账户密码分别是&#xff1a;root&#xff0c;toor。小写&#xff01;3然后直接输入&#xff1a;ipkg-opt install samba就会自动下…

android .9编译,在Ubuntu 9.04下编译Android源码

一直都是刷官方的版本&#xff0c;准备自己编译一下刷机。首先是下载&#xff0c;Android的源码是托管在Linux Kernel的源码站点&#xff0c;所以版本工具是git。关于git的使用和安装请见我的另一篇文章《在Ubuntu Server上安装Git》。创建一个存放Andorid的目录&#xff0c;然…

android reshare.c病毒,恶意软件分析 URL链接扫描 免费在线病毒分析平台 | 魔盾安全分析...

META-INF/MANIFEST.MFtNDfEFTy~s{Cg\V/OxIl[Mf"JC E_UcB1$^x6"i]6U#3D5Tmw>20#&hG;bVl*XK]xJU"#k})ek?w&);ViFd0iCFvye{(jB9w%^!yEj2,DGAW|^8ws%bD*eQ6n]fI_w3_nP_gxWll)zf[}l[[Rpn7x7?vbxfuVzgOj^x^lZ,b;%TK7k^mro)AYQJ2o^sL/EDh"^qND9V|Gn(…

imeoptions android,软键盘小记Android:imeOptions

1.actionUnspecified 未指定,对应常量EditorInfo.IME_ACTION_UNSPECIFIED.2.actionNone 没有动作,对应常量EditorInfo.IME_ACTION_NONE3.actionGo 去往,对应常量EditorInfo.IME_ACTION_GO4.actionSearch 搜索,对应常量EditorInfo.IME_ACTION_SEARCH5.actionSend 发送,对应常量E…

android rn框架开发的例子,RN与安卓通信架构篇

本篇文章介绍的搭建Android与Rn之间的简易通信架构&#xff0c;需要了解通信的基本使用的同学可以参考下面的链接开篇先上图 - “简易版的通信架构图”RN与Android之间通信的架构图本架构实现的功能有&#xff1a;自定义通信规则&#xff0c;并以Json作为数据传输格式进行传输实…

android 查询所有图片和视频,Android系统详解之获取图片和视频的缩略图

从Android 2.2开始系统新增了一个缩略图ThumbnailUtils类&#xff0c;位于framework的android.media.ThumbnailUtils位置&#xff0c;可以帮助我们从mediaprovider中获取系统中的视频或图片文件的缩略图&#xff0c;该类提供了三种静态方法可以直接调用获取。1.static Bitmap c…

node将图片转换成html文件,node+puppeteer将整个网页html转换为图片并保存【滚动截屏】...

Puppeteer 是 Chrome 开发团队在 2017 年发布的一个 Node.js 包&#xff0c;用来模拟 Chrome 浏览器的运行。demo只支持将简单不需要翻页&#xff0c;不需要登陆的页面转换为图片需要node环境&#xff0c;以及npm或cnpm包管理工具(自行百度)开始进入一个新的项目目录&#xff0…

html hover效果下拉个框,关于下拉菜单(CSS)中,“:hover”样式的设置问题?

各位大大&#xff0c;请帮忙解决一下这个问题&#xff0c;先谢谢&#xff01;由于之前的代码不是全部帖出&#xff0c;可能造成一点信息误解。以下是针对这个问题另外写的代码&#xff1a;.nav {width: 50px;height: 50px;overflow:hidden;background-color: #09F;transition: …

计算机基础知识离线作业答案,浙大远程教育计算机离线作业1.计算机基础知识题...

浙大远程教育计算机离线作业1.计算机基础知识题第1章 计算机基础知识(单选题)这些题目必须做一遍&#xff0c;来自统考题库(期末考试题也多半出在这里)&#xff0c;参考答案在另一个Word文档中(上传自己做的答案后才可以下载…)。据说&#xff0c;统考题库中大约有10,000测试题…

go 生成hash_go基础之map-写在前面(一)

为什么分析map在计算机编程语言当中&#xff0c;用的最多的数据结构估计就是map。map以他近乎o(1)的查找效率和修改效率让他在大多数场景下都比较受青睐。map的常规的实现方式都是hash其他数据结构&#xff0c;如java是hash红黑树&#xff0c;而我现在即将要分析的go的实现方式…

大学数学建模大赛是用计算机,北京大学第十届“江泽涵杯”数学建模与计算机应用竞赛试题...

消息来源&#xff1a;http://www.math.pku.edu.cn:8000/news/read.php?newsid8014A题&#xff1a;投篮问题投篮是篮球运动中一项关键性技术&#xff0c;是一项重要的得分手段。在篮球赛中有三种特殊的投篮方式&#xff0c;“三分球”、“两分球”和“一分球(罚篮)”。其中&…

dynamo方程怎么写_【简明自控】为什么特征方程如此重要

简明自动控制——为什么特征方程如此重要。热场视频&#xff1a;自平衡杆-双轴反作用轮倒立摆_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.com顶个棍子&#xff01;具有主动脚轮的全向移动机器人_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili​www.bilibili.com我自行车怎么少…

用户计算机可以通过电话拨号,用户计算机可以通过大型局域网、小型局域网、无线连接、电话拨号和()等方式接入Internet。...

_在保险合同中&#xff0c;用于体现保险利益载体的保险对象条款&#xff0c;被称为()条款。何为C/H比&#xff1f;原料中的C/H比与原性能的关系是什么&#xff1f;选址意见书、规划条件、建设用地规划许可证、建设工程规划许可证的有效期为()福建木偶戏颇负盛名&#xff0c;以(…