MFC对话框实现模糊c均值聚类算法

来源:互联网 发布:java extends super 编辑:程序博客网 时间:2024/06/05 17:16

       程序非常简单,作为当初我的第一个MFC程序,有纪念意义。程序最终界面:

          

一、问题:在MFC对话框界面输入任意类别和任意数目的样本进行C分类,并进行显示。

二、c均值聚类算法

1、c—平均算法

         对一批没有标明类别及类数的模式样本集,根据模式间的相似程度,按照物以类聚、人以群分的思想,将相似的模式分为一类,不相似的分为另一类。c均值聚类算法根据欧式距离把最短距离的样本分为1类。

     

                                                                                          

                            动态聚类框图

  ①  先选定某种距离作为样本间的相似性的度量;

  ②  确定评价聚类结果的准则函数;

  ③  给出某种初始分类,用迭代法找出使准则函数取极值的最好的聚类结果。

2、算法步骤

    ① 根据输入的分类数和样本总数,生成坐标范围内的随机数

    ② 初始聚类中心

    ③ 根据欧式距离进行一次分类

   ④ 根据新分成的两建立新的聚类中心

   ⑤ 新旧聚类中心不等则转回③,相等结束计算

   ⑥ 绘图显示结果

三、动态存储点坐标的数据结构

       由于要求输入任意类别和任意数目样本,所以存放数据不能放在一般的数组(因为必须进行初始化,不然编译不过)。而每个样本数据有几个特征,所以它实际是一个第一维未知、第二维已知(如这里的xy坐标)的动态数组。有几种方法:

① 用new[]定义一个一维动态数组指针(结构体对象指针),在程序运行时按界面输入样本多少分配内存。第二维的样本特征可以用个结构体,如:

struct mypoint

{

       int x;

       int y;

       int myclass;//类别

 };

mypoint*  ptr=new mypoint[num];

②用自带的cpoint类自己定义一个坐标对象,用new[]定义一个相应对象的一维数组指针

③容器。我另一个程序的一部分:

class CModel  

{

public:

         CModel();

          virtual ~CModel();

         int class_num;   //样本数目

         int value[3]; //第二维样本特征

};

struct sq

{

         int xclass;

         int ysq;

};

vector<sq>vec_p(classnum+2);

vector<CModel> vec_point(num);

vector<CModel>::size_type vector_size=num;

for (vector<CModel>::size_type it = (v-1)*num/classnum; it != v*num/classnum; ++it)

{……}

④定义个动态二维数组,第二维已知。比如我们一般的用法:

char (*a)[N];//指向数组的指针

a = new char[m][N];

delete[] a;

四、程序实现

① cmathDlg.h

#pragma once#include <vector>// CcmathDlg 对话框class CcmathDlg : public CDialog{// 构造public:CcmathDlg(CWnd* pParent = NULL);// 标准构造函数void DrawOnMem();double random(double start, double end);// 对话框数据enum { IDD = IDD_CMATH_DIALOG };protected:virtual void DoDataExchange(CDataExchange* pDX);// DDX/DDV 支持// 实现protected:HICON m_hIcon;// 生成的消息映射函数virtual BOOL OnInitDialog();afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();DECLARE_MESSAGE_MAP()public:afx_msg void OnBnClickedOk();int num;int classnum;vector<int> vec_point;};struct mypoint{int x;int y;int myclass;};struct myxy{int x;int y;int k;};

②cmathDlg.cpp

// cmathDlg.cpp : 实现文件//#include "stdafx.h"#include "cmath.h"#include "cmathDlg.h"#include "Resource.h"#include"time.h"#include "math.h"#ifdef _DEBUG#define new DEBUG_NEW#endif// CcmathDlg 对话框CcmathDlg::CcmathDlg(CWnd* pParent /*=NULL*/): CDialog(CcmathDlg::IDD, pParent), num(0), classnum(0){m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CcmathDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);DDX_Text(pDX, IDC_EDIT1, num);DDV_MinMaxInt(pDX, num, 2, 100);DDX_Text(pDX, IDC_EDIT2, classnum);DDV_MinMaxInt(pDX, classnum, 2, 100);}BEGIN_MESSAGE_MAP(CcmathDlg, CDialog)ON_WM_PAINT()ON_WM_QUERYDRAGICON()//}}AFX_MSG_MAPON_BN_CLICKED(IDOK, &CcmathDlg::OnBnClickedOk)END_MESSAGE_MAP()// CcmathDlg 消息处理程序BOOL CcmathDlg::OnInitDialog(){CDialog::OnInitDialog();// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动//  执行此操作SetIcon(m_hIcon, TRUE);// 设置大图标SetIcon(m_hIcon, FALSE);// 设置小图标// TODO: 在此添加额外的初始化代码return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE}// 如果向对话框添加最小化按钮,则需要下面的代码//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,//  这将由框架自动完成。void CcmathDlg::OnPaint(){if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}DrawOnMem();}//当用户拖动最小化窗口时系统调用此函数取得光标//显示。HCURSOR CcmathDlg::OnQueryDragIcon(){return static_cast<HCURSOR>(m_hIcon);}void CcmathDlg::OnBnClickedOk(){InvalidateRect(NULL,TRUE);UpdateWindow();UpdateData(TRUE);CClientDC  dc(this); int x1,x2,y1,y2,m;int p=0;intlg=30;        bool f;        mypoint*  ptr=new mypoint[num];myxy* double_ptr=new  myxy[classnum];        myxy* double_ptr1=new  myxy[classnum];srand(unsigned(time(0)));ptr[0].x=int(random(0,11));ptr[0].y=int(random(0,11));        ptr[0].myclass=0;        for(int icnt = 1; icnt != num; icnt++){          do  {   f=true;           ptr[icnt].x=int(random(0,11));                   ptr[icnt].y=int(random(0,11));           for(int j=0;j<icnt;j++)           {                                 if(ptr[icnt].x!=ptr[j].x||ptr[icnt].y!=ptr[j].y)continue;                                 if(j=icnt-1)                f=false;           }  }while(f==false);                  ptr[icnt].myclass=0;}    //第一步     for(int icnt = 0; icnt != classnum; icnt++)     {  double_ptr[icnt].x=ptr[icnt].x;          double_ptr[icnt].y=ptr[icnt].y;     }     double_ptr1=double_ptr;     //第二步     do     {          double_ptr1=double_ptr;   for(int icnt = 0; icnt != classnum; icnt++)          {double_ptr[icnt].k=0;                  }          for(int i = 0; i!= num; i++)  {                for(int j = 0; j!= classnum; j++)               {                     m= ptr[i].myclass;     ptr[i].myclass=(sqrt((double)((ptr[i].x-double_ptr[m].x)*(ptr[i].x-double_ptr[m].x)+(ptr[i].y-double_ptr[m].y)*(ptr[i].y-double_ptr[m].y)))>sqrt(((double)(ptr[i].x-double_ptr[j].x)*(ptr[i].x-double_ptr[j].x)+(ptr[i].y-double_ptr[j].y)*(ptr[i].y-double_ptr[j].y))))?j:m;       }  }          //第三步         for(int i = 0; i!= num; i++)         {             for(int j = 0; j!= classnum; j++)            {                 if(ptr[i].myclass==j){ double_ptr[j].x+=ptr[i].x;                         double_ptr[j].y+=ptr[i].y;                         double_ptr[j].k++; }      }        }        for(int j = 0; j!= classnum; j++)        {    if(double_ptr[j].k!=0)   {double_ptr[j].x=double_ptr[j].x/double_ptr[j].k;                double_ptr[j].y=double_ptr[j].y/double_ptr[j].k;   }     else   {               double_ptr[j].x=0;       double_ptr[j].y=0;  }       }       ++p;    }while(double_ptr1!=double_ptr);    for(int i=0; i< num; i++)    {           x1=20+ptr[i].x*lg-6; x2=20+ptr[i].x*lg+6; y1=360-ptr[i].y*lg+6; y2=360-ptr[i].y*lg-6;         switch(ptr[i].myclass) {      case 0:            {    CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(0,0,255));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;      }                       case 1:      {   CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(0,255,0));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;      }              case 2:     {   CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(255,0,0));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);                   break;    }            case 3:   {   CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(0,255,255));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;   }   case 4:   {    CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(255,0,255));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;   }           case 5:   {    CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(255,255,0));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;   }              case 6:   {    CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(0,0,0));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;  }           case 7:           {     CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(125,125,125));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;   }           case 8:   {    CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(125,0,255));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;   }           case 9:   {    CBrush brush,*oldbrush;                   brush.CreateSolidBrush(RGB(125,125,255));                   oldbrush=dc.SelectObject(&brush);                   dc.Ellipse(x1,y1,x2,y2);                   dc.SelectObject(oldbrush);   break;   }       }   }}void CcmathDlg::DrawOnMem(){    CString str;    int i;    CClientDC  dc(this);     CPen pen(PS_SOLID, 1, RGB(255, 0, 0));    CPen* pOldPen=dc.SelectObject(&pen);    dc.MoveTo(20, 20);     dc.LineTo(20, 360);     dc.LineTo(360, 360);     for(i = 0; i <= 10; i ++)    {        str.Format("%d", i);        dc.TextOut(17 + 30 * i, 365, str);        dc.MoveTo(i * 30 + 20, 360);        dc.LineTo(i * 30 + 20, 355);    }    str="x轴";    dc.TextOut(350,340,str);    for(i = 1; i <= 10; i ++)    {        str.Format("%d", i);        dc.TextOut(2, 360 - 30 * i - 5, str);        dc.MoveTo(25, 360 - 30 * i);        dc.LineTo(20, 360 - 30 * i);    }    str="y轴";    dc.TextOut(30,20,str);    dc.MoveTo(350, 357);    dc.LineTo(360, 360);    dc.LineTo(350, 363);     dc.MoveTo(17, 30);    dc.LineTo(20, 20);     dc.LineTo(23, 30);     dc.SelectObject(pOldPen);}double CcmathDlg::random(double start, double end){    return start+(end-start)*rand()/(RAND_MAX + 1.0);}