最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

用C++實現DBSCAN聚類算法

 更新時間:2013年05月24日 16:45:52   作者:  
本篇文章是對使用C++實現DBSCAN聚類算法的方法進行了詳細的分析介紹,需要的朋友參考下
這幾天由于工作需要,對DBSCAN聚類算法進行了C++的實現。時間復雜度O(n^2),主要花在算每個點領域內的點上。算法很簡單,現共享大家參考,也希望有更多交流。
 數據點類型描述如下:
復制代碼 代碼如下:

#include <vector>

 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<unsigned long> 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<unsigned long>& 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<DIME_NUM;i++)
     {
         this->dimension[i]=dimension[i];
     }
 }

 //設置維度數據
 void DataPoint::SetDimension(double* dimension)
 {
     for(int i=0; i<DIME_NUM;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<unsigned long>& DataPoint::GetArrivalPoints()
 {
     return arrivalPoints;
 }

DBSCAN算法類型描述:
復制代碼 代碼如下:

#include <iostream>
 #include <cmath>

 using namespace std;

 //聚類分析類型
 class ClusterAnalysis
 {
 private:
     vector<DataPoint> 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 );    //對數據點領域內的點執(zhí)行聚類操作
 public:

     ClusterAnalysis(){}                    //默認構造函數
     bool Init(char* fileName, double radius, int minPTs);    //初始化操作
     bool DoDBSCANRecursive();            //DBSCAN遞歸算法
     bool WriteToFile(char* fileName);    //將聚類結果寫入文件
 };

 聚類實現:
復制代碼 代碼如下:

#include "ClusterAnalysis.h"
 #include <fstream>
 #include <iosfwd>
 #include <math.h>

 /*
 函數:聚類初始化操作
 說明:將數據文件名,半徑,領域最小數據個數信息寫入聚類算法類,讀取文件,把數據信息讀入寫進算法類數據集合中
 參數:
 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;            //數據個數統(tǒng)計
     while (! ifs.eof() )                //從文件中讀取POI信息,將POI信息寫入POI列表中
     {
         DataPoint tempDP;                //臨時數據點對象
         double tempDimData[DIME_NUM];    //臨時數據點維度信息
         for(int j=0; j<DIME_NUM; 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<dataNum;i++)
     {
         SetArrivalPoints(dadaSets[i]);            //計算數據點領域內對象
     }
     return true;    //返回
 }

 /*
 函數:將已經過聚類算法處理的數據集合寫回文件
 說明:將已經過聚類結果寫回文件
 參數:
 char* fileName;    //要寫入的文件名
 返回值: true    */
 bool ClusterAnalysis::WriteToFile(char* fileName )
 {
     ofstream of1(fileName);                                //初始化文件輸出流
     for(unsigned long i=0; i<dataNum;i++)                //對處理過的每個數據點寫入文件
     {
         for(int d=0; d<DIME_NUM ; d++)                    //將維度信息寫入文件
             of1<<dadaSets[i].GetDimension()[d]<<'\t';
         of1 << dadaSets[i].GetClusterId() <<endl;        //將所屬簇ID寫入文件
     }
     of1.close();    //關閉輸出文件流
     return true;    //返回
 }

 /*
 函數:設置數據點的領域點列表
 說明:設置數據點的領域點列表
 參數:
 返回值: true;    */
 void ClusterAnalysis::SetArrivalPoints(DataPoint& dp)
 {
     for(unsigned long i=0; i<dataNum; i++)                //對每個數據點執(zhí)行
     {
         double distance =GetDistance(dadaSets[i], dp);    //獲取與特定點之間的距離
         if(distance <= radius && i!=dp.GetDpId())        //若距離小于半徑,并且特定點的id與dp的id不同執(zhí)行
             dp.GetArrivalPoints().push_back(i);            //將特定點id壓力dp的領域列表中
     }
     if(dp.GetArrivalPoints().size() >= minPTs)            //若dp領域內數據點數據量> minPTs執(zhí)行
     {
         dp.SetKey(true);    //將dp核心對象標志位設為true
         return;                //返回
     }
     dp.SetKey(false);    //若非核心對象,則將dp核心對象標志位設為false
 }

 
 /*
 函數:執(zhí)行聚類操作
 說明:執(zhí)行聚類操作
 參數:
 返回值: true;    */
 bool ClusterAnalysis::DoDBSCANRecursive()
 {
     unsigned long clusterId=0;                        //聚類id計數,初始化為0
     for(unsigned long i=0; i<dataNum;i++)            //對每一個數據點執(zhí)行
     {
         DataPoint& dp=dadaSets[i];                    //取到第i個數據點對象
         if(!dp.isVisited() && dp.IsKey())            //若對象沒被訪問過,并且是核心對象執(zhí)行
         {
             dp.SetClusterId(clusterId);                //設置該對象所屬簇ID為clusterId
             dp.SetVisited(true);                    //設置該對象已被訪問過
             KeyPointCluster(i,clusterId);            //對該對象領域內點進行聚類
             clusterId++;                            //clusterId自增1
         }
         //cout << "孤立點\T" << i << endl;
     }

     cout <<"共聚類" <<clusterId<<"個"<< endl;        //算法完成后,輸出聚類個數
     return true;    //返回
 }

 /*
 函數:對數據點領域內的點執(zhí)行聚類操作
 說明:采用遞歸的方法,深度優(yōu)先聚類數據
 參數:
 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<unsigned long>& arrvalPoints = srcDp.GetArrivalPoints();        //獲取對象領域內點ID列表
     for(unsigned long i=0; i<arrvalPoints.size(); i++)
     {
         DataPoint& desDp = dadaSets[arrvalPoints[i]];    //獲取領域內點數據點
         if(!desDp.isVisited())                            //若該對象沒有被訪問過執(zhí)行
         {
             //cout << "數據點\t"<< desDp.GetDpId()<<"聚類ID為\t" <<clusterId << endl;
             desDp.SetClusterId(clusterId);        //設置該對象所屬簇的ID為clusterId,即將該對象吸入簇中
             desDp.SetVisited(true);                //設置該對象已被訪問
             if(desDp.IsKey())                    //若該對象是核心對象
             {
                 KeyPointCluster(desDp.GetDpId(),clusterId);    //遞歸地對該領域點數據的領域內的點執(zhí)行聚類操作,采用深度優(yōu)先方法
             }
         }
     }
 }

 //兩數據點之間距離
 /*
 函數:獲取兩數據點之間距離
 說明:獲取兩數據點之間的歐式距離
 參數:
 DataPoint& dp1;        //數據點1
 DataPoint& dp2;        //數據點2
 返回值: double;    //兩點之間的距離        */
 double ClusterAnalysis::GetDistance(DataPoint& dp1, DataPoint& dp2)
 {
     double distance =0;        //初始化距離為0
     for(int i=0; i<DIME_NUM;i++)    //對數據每一維數據執(zhí)行
     {
         distance += pow(dp1.GetDimension()[i] - dp2.GetDimension()[i],2);    //距離+每一維差的平方
     }
     return pow(distance,0.5);        //開方并返回距離
 }

算法調用就簡單了:
復制代碼 代碼如下:

#include "ClusterAnalysis.h"
 #include <cstdio>

 using namespace std;

 int main()
 {
     ClusterAnalysis myClusterAnalysis;                        //聚類算法對象聲明
     myClusterAnalysis.Init("D:\\1108\\XY.txt",500,9);        //算法初始化操作,指定半徑為15,領域內最小數據點個數為3,(在程序中已指定數據維度為2)
     myClusterAnalysis.DoDBSCANRecursive();                    //執(zhí)行聚類算法
     myClusterAnalysis.WriteToFile("D:\\1108\\XYResult.txt");//寫執(zhí)行后的結果寫入文件

     system("pause");    //顯示結果
     return 0;            //返回
 }
您可能感興趣的文章:

相關文章

  • C++中的delete不會將操作數置0

    C++中的delete不會將操作數置0

    這篇文章主要介紹了C++中的delete不會將操作數置0的相關資料,需要的朋友可以參考下
    2016-05-05
  • C語言用封裝方法實現飛機大戰(zhàn)游戲

    C語言用封裝方法實現飛機大戰(zhàn)游戲

    這篇文章主要為大家詳細介紹了C語言用封裝方法實現飛機大戰(zhàn)游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 詳解C++?functional庫中的仿函數使用方法

    詳解C++?functional庫中的仿函數使用方法

    仿函數(functor)又稱之為函數對象(function?object),實際上就是?重載了()操作符?的?struct或class。本文將詳細講解C++中仿函數的使用方法,需要的可以參考一下
    2022-04-04
  • C語言常見排序算法之交換排序(冒泡排序,快速排序)

    C語言常見排序算法之交換排序(冒泡排序,快速排序)

    這篇文章主要介紹了C語言常見排序算法之交換排序(冒泡排序,快速排序),冒泡排序即Bubble?Sort,類似于水中冒泡,較大的數沉下去,較小的數慢慢冒起來,假設從小到大,即為較大的數慢慢往后排,較小的數慢慢往前排
    2022-07-07
  • 基于Qt Qml實現時間軸組件

    基于Qt Qml實現時間軸組件

    時間軸組件是現代用戶界面中常見的元素,用于按時間順序展示事件,本文主要為大家詳細介紹了如何使用Qml實現一個簡單的時間軸組件,需要的可以參考下
    2025-01-01
  • C++構造和解析Json的使用示例

    C++構造和解析Json的使用示例

    今天小編就為大家分享一篇關于C++構造和解析Json的使用示例,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • C++中rapidjson組裝繼續(xù)簡化的方法

    C++中rapidjson組裝繼續(xù)簡化的方法

    今天小編就為大家分享一篇關于C++中rapidjson組裝繼續(xù)簡化的方法,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • c++中的4種類型轉化方式詳細解析

    c++中的4種類型轉化方式詳細解析

    const_cast該函數用于去除指針變量的常量屬性,將它轉換為一個對應指針類型的普通變量。反過來,也可以將一個非常量的指針變量轉換為一個常指針變量
    2013-10-10
  • C/C++實現動態(tài)數組的示例詳解

    C/C++實現動態(tài)數組的示例詳解

    動態(tài)數組相比于靜態(tài)數組具有更大的靈活性,因為其大小可以在運行時根據程序的需要動態(tài)地進行分配和調整,本文為大家介紹了C++實現動態(tài)數組的方法,需要的可以參考下
    2023-08-08
  • 基于C++編寫一個文章生成器

    基于C++編寫一個文章生成器

    這篇文章主要為大家介紹一個有趣的小程序,就是利用C++編寫一個文章生成器,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-03-03

最新評論

嘉祥县| 琼海市| 泉州市| 康保县| 乳山市| 东安县| 永安市| 九台市| 拜城县| 北川| 开原市| 无极县| 托里县| 诸暨市| 天祝| 工布江达县| 衡阳县| 永清县| 远安县| 九寨沟县| 耒阳市| 元朗区| 漳平市| 思茅市| 北票市| 额尔古纳市| 黔南| 三江| 巴彦县| 宿迁市| 鲁山县| 新丰县| 吉水县| 宜都市| 河南省| 顺昌县| 东光县| 拉萨市| 施甸县| 长宁县| 克什克腾旗|