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

       程序非常简单,作为当初我的第一个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_MAP
	ON_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;
	int	lg=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);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值