模式识别之聚类算法k-均值---k-均值聚类算法c实现

//写个简单的先练习一下,测试通过
//k-均值聚类算法C语言版

  #include <stdlib.h>
     #include <stdio.h>
     #include <time.h>
     #include <math.h>
    #define TRUE             1
    #define FALSE            0
    int N;//数据个数
   int K;//集合个数
   int * CenterIndex;//初始化质心数组的索引
   double * Center;//质心集合
   double * CenterCopy;//质心集合副本
   double * AllData;//数据集合
   double ** Cluster;//簇的集合
   int * Top;//集合中元素的个数,也会用作栈处理

//随机生成k个数x(0<=x<=n-1)作为起始的质心集合
void CreateRandomArray(int n, int k,int * center)
{
     int i=0;
     int j=0;    
     srand( (unsigned)time( NULL ) );
     for( i=0;i<k;++i)//随机生成k个数
     {
         int a=rand()%n;
         //判重
         for(j=0;j<i;j++)
         {
             if(center[j]==a)//重复
             {
                 break;
             }
         }
         if(j>=i)//如果不重复,加入
         {
             center[i]=a;
         }
         else
         {
             i--;
             //如果重复,本次重新随机生成
         }
     }    
}

//返回距离最小的质心的序号
int GetIndex(double value,double * center)
{
     int i=0;
     int index=i;//最小的质心序号
     double min=fabs(value-center[i]);//距质心最小距离
     for(i=0;i<K;i++)
     {
         if(fabs(value-center[i])<min)//如果比当前距离还小,更新最小的质心序号和距离值
         {
              index=i;
              min=fabs(value-center[i]);
         }
     }
     return index;
}

//拷贝质心数组到副本
void CopyCenter()
{
     int i=0;
     for(i=0;i<K;i++)
     {
         CenterCopy[i]=Center[i];
     }
}
//初始化质心,随机生成法
void InitCenter()
{
     int i=0;
     CreateRandomArray(N,K,CenterIndex);//产生随机的K个<N的不同的序列
     for(i=0;i<K;i++)
     {
         Center[i]=AllData[CenterIndex[i]];//将对应数据赋值给质心数组
     }
     CopyCenter();//拷贝到质心副本    
}
//加入一个数据到一个Cluster[index]集合
void AddToCluster(int index,double value)
{
     Cluster[index][Top[index]++]=value;//这里同进栈操作
}

//重新计算簇集合
void UpdateCluster()
{    
     int i=0;
     int tindex;
     //将所有的集合清空,即将TOP置0
     for(i=0;i<K;i++)
     {
         Top[i]=0;
     }
     for(i=0;i<N;i++)
     {
         tindex=GetIndex(AllData[i],Center);//得到与当前数据最小的质心索引
         AddToCluster(tindex,AllData[i]);    //加入到相应的集合中
     }
}
//重新计算质心集合,对每一簇集合中的元素加总求平均即可
void UpdateCenter()
{
     int i=0;
     int j=0;
     double sum=0;
     for(i=0;i<K;i++)
     {
         sum=0;    
         //计算簇i的元素和
         for(j=0;j<Top[i];j++)
          {
              sum+=Cluster[i][j];
          }
         if(Top[i]>0)//如果该簇元素不为空
         {
            Center[i]=sum/Top[i];//求其平均值
         }
     }
}
//判断2数组元素是否相等
int IsEqual(double * center1 ,double * center2)
{
     int i;
     for(i=0;i<K;i++)
     {
          if(fabs(center1[i]!=center2[i]))
          {
              return FALSE;
          }
     }
     return TRUE;
}
//打印聚合结果
void Print()
{
     int i,j;
     printf("-------------------------------------- ");
     for(i=0;i<K;i++)
     {
          printf("第%d组: 质心(%f) ",i,Center[i]);
           for(j=0;j<Top[i];j++)
           {
               printf("%f ",Cluster[i][j]);
           }          
     }    
}
//初始化聚类的各种数据
void InitData()
{
     int i=0;
     int a;
     printf("输入数据个数: ");    
     scanf("%d",&N);
     printf("输入簇个数: ");    
     scanf("%d",&K);    
     if(K>N)
     {
         exit(0);
     }
     Center=(double *)malloc(sizeof(double)*K);//为质心集合申请空间
     CenterIndex=(int *)malloc(sizeof(int)*K);//为质心集合索引申请空间
     CenterCopy=(double *)malloc(sizeof(double)*K);//为质心集合副本申请空间
     Top=(int *)malloc(sizeof(int)*K);
     AllData=(double *)malloc(sizeof(double)*N);//为数据集合申请空间
     Cluster=(double **)malloc(sizeof(double *)*K);//为簇集合申请空间
     //初始化K个簇集合
     for(i=0;i<K;i++)
     {
         Cluster[i]=(double *)malloc(sizeof(double)*N);
         Top[i]=0;
     }
     printf("输入%d数据:",N);
     for(i=0;i<N;i++)
     {
         scanf("%d",&(a));
         AllData[i]=a;
     }
     InitCenter();//初始化质心集合      
     UpdateCluster();//初始化K个簇集合

}
/*
算法描述:
K均值算法:
     给定类的个数K,将N个对象分到K个类中去,
     使得类内对象之间的相似性最大,而类之间的相似性最小。
*/
main()
{
     int Flag=1;//迭代标志,若为false,则迭代结束
     int i=0;
     InitData();//初始化数据      
     while(Flag)//开始迭代
     {
          UpdateCluster();//更新各个聚类
          UpdateCenter(); //更新质心数组
          if(IsEqual(Center,CenterCopy))//如果本次迭代与前次的质心聚合相等,即已收敛,结束退出
          {
              Flag=0;
          }
          else//否则将质心副本置为本次迭代得到的的质心集合
          {
              CopyCenter();//将质心副本置为本次迭代得到的的质心集合
          }
     }
     Print();//输出结果
     getchar();
     getchar();

}
时间: 2024-10-23 13:06:47

模式识别之聚类算法k-均值---k-均值聚类算法c实现的相关文章

k-均值聚类算法;二分k均值聚类算法

根据<机器学习实战>一书第十章学习k均值聚类算法和二分k均值聚类算法,自己把代码边敲边理解了一下,修正了一些原书中代码的细微差错.目前代码有时会出现如下4种报错信息,这有待继续探究和完善. 报错信息: Warning (from warnings module): File "F:\Python2.7.6\lib\site-packages\numpy\core\_methods.py", line 55 warnings.warn("Mean of empty

算法导论----贪心算法,删除k个数,使剩下的数字最小

先贴问题: 1个n位正整数a,删去其中的k位,得到一个新的正整数b,设计一个贪心算法,对给定的a和k得到最小的b: 一.我的想法:先看例子:a=5476579228:去掉4位,则位数n=10,k=4,要求的最小数字b是n-k=6位的: 1.先找最高位的数,因为是6位数字,所以最高位不可能在后5位上取到(因为数字的相对顺序是不能改变的,假设如果取了后五位中倒数第5位的7,则所求的b就不可能是6位的了,最多也就是4位的79228)理解这点很重要!所以问题变成从第1位到第k+1(n-(n-k-1))取

查找第K小的数 BFPRT算法

BFPRT算法是解决从n个数中选择第k大或第k小的数这个经典问题的著名算法,但很多人并不了解其细节.本文将首先介绍求解这个第k小数字问题的几个思路,然后重点介绍在最坏情况下复杂度仍然为O(n)的BFPRT算法. 一 基本思路 关于选择第k小的数有许多方法 将n个数排序(比如快速排序或归并排序),选取排序后的第k个数,时间复杂度为O(nlogn). 维护一个k个元素的最大堆,存储当前遇到的最小的k个数,时间复杂度为O(nlogk).这种方法同样适用于海量数据的处理. 部分的快速排序(快速选择算法)

编程算法 - 最小的k个数 代码(C)

最小的k个数 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入n个整数, 找出其中的最小k个数. 使用快速排序(Quick Sort)的方法求解, 把索引值(index)指向前k个数. 代码: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */ /*eclipse cdt, gcc 4.8.1*/ #include <stdio.h> #include <stdl

编程算法 - 最小的k个数 红黑树 代码(C++)

最小的k个数 红黑树 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 输入n个整数, 找出其中的最小k个数. 使用红黑树(multiset), 每次替换最大的值, 依次迭代. 时间复杂度: O(nlogk). 代码: /* * main.cpp * * Created on: 2014年6月29日 * Author: wang */ #include <iostream> #include <vector> #includ

[算法]字符串左移k位

如,abcde左移3位为deabc 要求时间复杂度O(n),空间复杂度O(1),每一个字符只能遍历一次 摘自http://blog.csdn.net/geniusluzh/article/details/8460031 利用数学解决该问题 其实对于这道题,最初一看的想法就是将当前位依次替换左移m位对应的那个位,然后依次替换.后来发现有的情况一次循环替换就能全部完成整个串的左移,而有的情况下会出现多个循环链,一时只得到规律,不能想到很好的证明办法,只怪以前初等数论没有好好学啊! 我们发现对于长度为

1501130926-蓝桥杯- 算法训练 区间k大数查询

算法训练 区间k大数查询 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m,表示询问个数. 接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个.序列元素从1开始标号. 输出格式 总共输出m行,每行一个数,表示询问的答案. 样例输入 5 1 2 3 4 5 2 1

蓝桥杯--算法训练 区间k大数查询

算法训练 区间k大数查询 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m,表示询问个数. 接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个.序列元素从1开始标号. 输出格式 总共输出m行,每行一个数,表示询问的答案. 样例输入 51 2 3 4 521 5

POJ2449Remmarguts&#39; Date(A*算法求第K小路)

Remmarguts' Date Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 21084   Accepted: 5740 Description "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. Softly touching his little ducks' head, h