欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語(yǔ)言中K-means算法實(shí)現(xiàn)代碼

 更新時(shí)間:2018年02月23日 11:39:33   作者:_席達(dá)_  
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言中K-means算法的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

K-means算法是很典型的基于距離的聚類(lèi)算法,采用距離作為相似性的評(píng)價(jià)指標(biāo),即認(rèn)為兩個(gè)對(duì)象的距離越近,其相似度就越大。該算法認(rèn)為簇是由距離靠近的對(duì)象組成的,因此把得到緊湊且獨(dú)立的簇作為最終目標(biāo)。

算法過(guò)程如下:

1)從N個(gè)樣本隨機(jī)選取K個(gè)樣本作為質(zhì)心
2)對(duì)剩余的每個(gè)樣本測(cè)量其到每個(gè)質(zhì)心的距離,并把它歸到最近的質(zhì)心的類(lèi)
3)重新計(jì)算已經(jīng)得到的各個(gè)類(lèi)的質(zhì)心
4)迭代2~3步直至新的質(zhì)心與原質(zhì)心相等或小于指定閾值,算法結(jié)束

#include<stdio.h> 
#include<stdlib.h> 
#include<string.h> 
#include<time.h> 
#include<math.h> 
 
#define DIMENSIOM  2    //目前只是處理2維的數(shù)據(jù) 
#define MAX_ROUND_TIME 100   //最大的聚類(lèi)次數(shù) 
 
typedef struct Item{ 
  int dimension_1;    //用于存放第一維的數(shù)據(jù) 
  int dimension_2;    //用于存放第二維的數(shù)據(jù) 
  int clusterID;     //用于存放該item的cluster center是誰(shuí) 
}Item; 
Item* data; 
 
typedef struct ClusterCenter{ 
  double dimension_1; 
  double dimension_2; 
  int clusterID; 
}ClusterCenter; 
ClusterCenter* cluster_center_new; 
 
int isContinue; 
 
int* cluster_center;    //記錄center 
double* distanceFromCenter; //記錄一個(gè)“點(diǎn)”到所有center的距離 
int data_size; 
char filename[200]; 
int cluster_count; 
 
void initial(); 
void readDataFromFile(); 
void initial_cluster(); 
void calculateDistance_ToOneCenter(int itemID, int centerID, int count); 
void calculateDistance_ToAllCenter(int itemID); 
void partition_forOneItem(int itemID); 
void partition_forAllItem_OneCluster(int round); 
void calculate_clusterCenter(int round); 
void K_means(); 
void writeClusterDataToFile(int round); 
void writeClusterCenterToFile(int round); 
void compareNew_OldClusterCenter(double* new_X_Y); 
void test_1(); 
 
int main(int argc, char* argv[]){ 
  if( argc != 4 ) 
  { 
    printf("This application need other parameter to run:" 
        "\n\t\tthe first is the size of data set," 
        "\n\t\tthe second is the file name that contain data" 
        "\n\t\tthe third indicate the cluster_count" 
        "\n"); 
    exit(0); 
  } 
  srand((unsigned)time(NULL)); 
  data_size = atoi(argv[1]); 
  strcat(filename, argv[2]); 
  cluster_count = atoi(argv[3]); 
 
  initial(); 
  readDataFromFile(); 
  initial_cluster(); 
  //test_1(); 
  //partition_forAllItem_OneCluster(); 
  //calculate_clusterCenter(); 
  K_means(); 
  return 0; 
} 
 
/* 
 * 對(duì)涉及到的二維動(dòng)態(tài)數(shù)組根據(jù)main函數(shù)中傳入的參數(shù)分配空間 
 * */ 
void initial(){ 
  data = (Item*)malloc(sizeof(struct Item) * (data_size + 1)); 
  if( !data ) 
  { 
    printf("malloc error:data!"); 
    exit(0); 
  } 
  cluster_center = (int*)malloc(sizeof(int) * (cluster_count + 1)); 
  if( !cluster_center ) 
  { 
    printf("malloc error:cluster_center!\n"); 
    exit(0); 
  } 
  distanceFromCenter = (double*)malloc(sizeof(double) * (cluster_count + 1)); 
  if( !distanceFromCenter ) 
  { 
    printf("malloc error: distanceFromCenter!\n"); 
    exit(0); 
  } 
  cluster_center_new = (ClusterCenter*)malloc(sizeof(struct ClusterCenter) * (cluster_count + 1)); 
  if( !cluster_center_new ) 
  { 
    printf("malloc cluster center new error!\n"); 
    exit(0); 
  } 
} 
 
/* 
 * 從文件中讀入x和y數(shù)據(jù) 
 * */ 
void readDataFromFile(){ 
  FILE* fread; 
  if( NULL == (fread = fopen(filename, "r"))) 
  { 
    printf("open file(%s) error!\n", filename); 
    exit(0); 
  } 
  int row; 
  for( row = 1; row <= data_size; row++ ) 
  { 
    if( 2 != fscanf(fread, "%d %d ", &data[row].dimension_1, &data[row].dimension_2)) 
    { 
      printf("fscanf error: %d\n", row); 
    } 
    data[row].clusterID = 0; 
  } 
} 
 
/* 
 * 根據(jù)從主函數(shù)中傳入的@cluster_count(聚類(lèi)的個(gè)數(shù))來(lái)隨機(jī)的選擇@cluster_count個(gè) 
 * 初始的聚類(lèi)的起點(diǎn) 
 * */ 
 
void initial_cluster(){ 
  //輔助產(chǎn)生不重復(fù)的數(shù) 
  int* auxiliary; 
  int i; 
  auxiliary = (int*)malloc(sizeof(int) * (data_size + 1)); 
  if( !auxiliary ) 
  { 
    printf("malloc error: auxiliary"); 
    exit(0); 
  } 
  for( i = 1; i <= data_size; i++ ) 
  { 
    auxiliary[i] = i; 
  } 
   
  //產(chǎn)生初始化的cluster_count個(gè)聚類(lèi) 
  int length = data_size; 
  int random; 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    random = rand()%length + 1; 
    //printf("%d \n", auxiliary[random]); 
    //data[auxiliary[random]].clusterID = auxiliary[random]; 
    cluster_center[i] = auxiliary[random]; 
    auxiliary[random] = auxiliary[length--]; 
  } 
   
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    cluster_center_new[i].dimension_1 = data[cluster_center[i]].dimension_1; 
    cluster_center_new[i].dimension_2 = data[cluster_center[i]].dimension_2; 
    cluster_center_new[i].clusterID = i; 
    data[cluster_center[i]].clusterID = i; 
  } 
} 
 
/* 
 * 計(jì)算一個(gè)點(diǎn)(還沒(méi)有劃分到cluster center的點(diǎn))到一個(gè)cluster center的distance 
 *   @itemID:  不屬于任何cluster中的點(diǎn) 
 *   @centerID: center的ID 
 *   @count:   表明在計(jì)算的是itemID到第幾個(gè)@center的distance,并且指明了結(jié)果放在distanceFromCenter的第幾號(hào)元素 
 * */ 
void calculateDistance_ToOneCenter(int itemID,int centerID){ 
  distanceFromCenter[centerID] = sqrt( (data[itemID].dimension_1-cluster_center_new[centerID].dimension_1)*(double)(data[itemID].dimension_1-cluster_center_new[centerID].dimension_1) + (double)(data[itemID].dimension_2-cluster_center_new[centerID].dimension_2) * (data[itemID].dimension_2-cluster_center_new[centerID].dimension_2) ); 
} 
 
/* 
 * 計(jì)算一個(gè)點(diǎn)(還沒(méi)有劃分到cluster center的點(diǎn))到每個(gè)cluster center的distance 
 * */ 
void calculateDistance_ToAllCenter(int itemID){ 
  int i; 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    calculateDistance_ToOneCenter(itemID, i); 
  } 
} 
 
void test_1() 
{ 
  calculateDistance_ToAllCenter(3); 
  int i; 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    printf("%f ", distanceFromCenter[i]); 
  } 
} 
 
/* 
 * 在得到任一的點(diǎn)(不屬于任一cluster的)到每一個(gè)cluster center的distance之后,決定它屬于哪一個(gè)cluster center,即取距離最小的 
 *   函數(shù)功能:得到一個(gè)item所屬的cluster center 
 * */ 
void partition_forOneItem(int itemID){ 
  //操作對(duì)象是 distanceFromCenter和cluster_center 
  int i; 
  int min_index = 1; 
  double min_value = distanceFromCenter[1]; 
  for( i = 2; i <= cluster_count; i++ ) 
  { 
    if( distanceFromCenter[i] < min_value ) 
    { 
      min_value = distanceFromCenter[i]; 
      min_index = i; 
    } 
  } 
 
  data[itemID].clusterID = cluster_center_new[min_index].clusterID; 
} 
 
/* 
 * 得到所有的item所屬于的cluster center , 在一輪的聚類(lèi)中 
 * */ 
void partition_forAllItem_OneCluster(int round){        //changed!!!!!!!!!!!!!!!!!!!!!!!! 
  int i; 
  for( i = 1; i <= data_size; i++ ) 
  { 
    if( data[i].clusterID != 0 ) 
      continue; 
    else 
    { 
      calculateDistance_ToAllCenter(i);  //計(jì)算i到所有center的distance 
      partition_forOneItem(i);    //根據(jù)distance對(duì)i進(jìn)行partition 
    } 
  } 
 
  //把聚類(lèi)得到的數(shù)據(jù)寫(xiě)入到文件中 
  writeClusterDataToFile(round); 
} 
 
/* 
 * 將聚類(lèi)得到的數(shù)據(jù)寫(xiě)入到文件中,每一個(gè)類(lèi)寫(xiě)入一個(gè)文件中 
 *   @round: 表明在進(jìn)行第幾輪的cluster,該參數(shù)的另一個(gè)作用是指定了文件名字中的第一個(gè)項(xiàng). 
 * */ 
void writeClusterDataToFile(int round){ 
  int i; 
  char filename[200]; 
  FILE** file; 
  file = (FILE**)malloc(sizeof(FILE*) * (cluster_count + 1)); 
  if( !file ) 
  { 
    printf("malloc file error!\n"); 
    exit(0); 
  } 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    sprintf(filename, ".//ClusterProcess//round%d_cluster%d.data", round, i); 
    if( NULL == (file[i] = fopen(filename, "w"))) 
    { 
      printf("file open(%s) error!", filename); 
      exit(0); 
    } 
  } 
   
  for( i = 1; i <= data_size; i++ ) 
  { 
    //sprintf(filename, ".//ClusterProcess//round%d_cluster%d.data", round, data[i].clusterID); 
    fprintf(file[data[i].clusterID], "%d\t%d\n", data[i].dimension_1, data[i].dimension_2); 
  } 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    //sprintf(filename, ".//ClusterProcess//round%d_cluster%d.data", round, i); 
    fclose(file[i]); 
  } 
} 
 
/* 
 * 重新計(jì)算新的cluster center 
 * */ 
void calculate_clusterCenter(int round){          //changed!!!!!!!!!!!!!!!!!!!!!! 
  int i; 
  double* new_X_Y;  /* 
          用來(lái)計(jì)算和保存新的cluster center的值,同樣的,0號(hào)元素不用。1,2號(hào)元素分別用來(lái) 
          存放第一個(gè)聚類(lèi)的所有的項(xiàng)的x和y的累加和。3,4號(hào)元素分別用來(lái)存放第二個(gè)聚類(lèi)的所有 
          的項(xiàng)的x和y的累加和...... 
        */ 
  new_X_Y = (double*)malloc(sizeof(double) * (2 * cluster_count + 1)); 
  if( !new_X_Y ) 
  { 
    printf("malloc error: new_X_Y!\n"); 
    exit(0); 
  } 
  //初始化為0 
  for( i = 1; i <= 2*cluster_count; i++ ) 
    new_X_Y[i] = 0.0; 
 
  //用來(lái)統(tǒng)計(jì)屬于各個(gè)cluster的item的個(gè)數(shù) 
  int* counter; 
  counter = (int*)malloc(sizeof(int) * (cluster_count + 1)); 
  if( !counter ) 
  { 
    printf("malloc error: counter\n"); 
    exit(0); 
  } 
  //初始化為0 
  for( i = 1; i <= cluster_count; i++ ) 
    counter[i] = 0; 
 
  for( i = 1; i <= data_size; i++ ) 
  { 
    new_X_Y[data[i].clusterID * 2 - 1] += data[i].dimension_1; 
    new_X_Y[data[i].clusterID * 2] += data[i].dimension_2; 
    counter[data[i].clusterID]++; 
  } 
 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    new_X_Y[2 * i - 1] = new_X_Y[2 * i - 1] / (double)(counter[i]); 
    new_X_Y[2 * i] = new_X_Y[2 * i] / (double)(counter[i]); 
  } 
   
  //要將cluster center的值保存在文件中,后續(xù)作圖 
  writeClusterCenterToFile(round); 
   
  /* 
   * 在這里比較一下新的和舊的cluster center值的差別。如果是相等的,則停止K-means算法。 
   * */ 
  compareNew_OldClusterCenter(new_X_Y); 
 
  //將新的cluster center的值放入cluster_center_new 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    cluster_center_new[i].dimension_1 = new_X_Y[2 * i - 1]; 
    cluster_center_new[i].dimension_2 = new_X_Y[2 * i]; 
    cluster_center_new[i].clusterID = i; 
  } 
  free(new_X_Y); 
  free(counter); 
 
  //在重新計(jì)算了新的cluster center之后,意味著我們要重新來(lái)為每一個(gè)Item進(jìn)行聚類(lèi),所以data中用于表示聚類(lèi)ID的clusterID 
  //要都重新置為0。 
  for( i = 1; i <= data_size; i++ ) 
  { 
    data[i].clusterID = 0; 
  } 
} 
 
/* 
 * 將得到的新的cluster_count個(gè)cluster center的值保存在文件中。以便于觀察聚類(lèi)的過(guò)程。 
 * */ 
void writeClusterCenterToFile(int round){ 
  FILE* file; 
  int i; 
  char filename[200]; 
  sprintf(filename, ".//ClusterProcess//round%d_clusterCenter.data", round); 
  if( NULL == (file = fopen(filename, "w"))) 
  { 
    printf("open file(%s) error!\n", filename); 
    exit(0); 
  } 
 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    fprintf(file, "%f\t%f\n", cluster_center_new[i].dimension_1, cluster_center_new[i].dimension_2); 
  } 
 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    fclose(file); 
  } 
} 
 
/* 
 * 比較新舊的cluster center的差異 
 * */ 
void compareNew_OldClusterCenter(double* new_X_Y){ 
  int i; 
  isContinue = 0;       //等于0表示的是不要繼續(xù) 
  for( i = 1; i <= cluster_count; i++ ) 
  { 
    if( new_X_Y[2 * i - 1] != cluster_center_new[i].dimension_1 || new_X_Y[2 * i] != cluster_center_new[i].dimension_2) 
    { 
      isContinue = 1;   //要繼續(xù) 
      break; 
    } 
  } 
} 
 
/************************************************************************************************ 
 *         K-means算法            *    
 ***********************************************************************************************/ 
void K_means(){ 
  int times_cluster; 
  for( times_cluster = 1; times_cluster <= MAX_ROUND_TIME; times_cluster++ ) 
  { 
    printf("\n            times : %d             \n", times_cluster); 
    partition_forAllItem_OneCluster(times_cluster); 
    calculate_clusterCenter(times_cluster); 
    if( 0 == isContinue ) 
    { 
      break; 
      //printf("\n\nthe application can stop!\n\n"); 
    } 
  } 
}

 

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

您可能感興趣的文章:

相關(guān)文章

  • C++基類(lèi)指針和派生類(lèi)指針之間的轉(zhuǎn)換方法講解

    C++基類(lèi)指針和派生類(lèi)指針之間的轉(zhuǎn)換方法講解

    今天小編就為大家分享一篇關(guān)于C++基類(lèi)指針和派生類(lèi)指針之間的轉(zhuǎn)換方法講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-04-04
  • C++ getline函數(shù)用法詳解

    C++ getline函數(shù)用法詳解

    這篇文章主要介紹了C++ getline函數(shù)用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • C++生成不重復(fù)的隨機(jī)整數(shù)

    C++生成不重復(fù)的隨機(jī)整數(shù)

    這篇文章主要為大家詳細(xì)介紹了C++生成不重復(fù)的隨機(jī)整數(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • 對(duì)C++ string append方法的常用用法詳解

    對(duì)C++ string append方法的常用用法詳解

    今天小編就為大家分享一篇對(duì)C++ string append方法的常用用法詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • C語(yǔ)言實(shí)現(xiàn)靜態(tài)存儲(chǔ)通訊錄的示例代碼

    C語(yǔ)言實(shí)現(xiàn)靜態(tài)存儲(chǔ)通訊錄的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)一個(gè)靜態(tài)存儲(chǔ)的通訊錄,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C語(yǔ)言有一定幫助,需要的可以參考一下
    2022-09-09
  • OpenCV實(shí)現(xiàn)圖像輪廓檢測(cè)以及外接矩形

    OpenCV實(shí)現(xiàn)圖像輪廓檢測(cè)以及外接矩形

    這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)圖像輪廓檢測(cè)以及外接矩形,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • C語(yǔ)言如何利用ASCII碼表統(tǒng)計(jì)字符串每個(gè)字符出現(xiàn)的次數(shù)

    C語(yǔ)言如何利用ASCII碼表統(tǒng)計(jì)字符串每個(gè)字符出現(xiàn)的次數(shù)

    這篇文章主要介紹了C語(yǔ)言如何利用ASCII碼表統(tǒng)計(jì)字符串每個(gè)字符出現(xiàn)的次數(shù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • C語(yǔ)言一個(gè)函數(shù)如何實(shí)現(xiàn)好幾個(gè)return返回值

    C語(yǔ)言一個(gè)函數(shù)如何實(shí)現(xiàn)好幾個(gè)return返回值

    本文主要介紹了C語(yǔ)言一個(gè)函數(shù)如何實(shí)現(xiàn)好幾個(gè)return返回值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • C++中rapidjson將map轉(zhuǎn)為json的方法

    C++中rapidjson將map轉(zhuǎn)為json的方法

    今天小編就為大家分享一篇關(guān)于C++中rapidjson將map轉(zhuǎn)為json的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-04-04
  • 探究C++中string類(lèi)的實(shí)現(xiàn)原理以及擴(kuò)展使用

    探究C++中string類(lèi)的實(shí)現(xiàn)原理以及擴(kuò)展使用

    這篇文章主要介紹了C++中string類(lèi)的實(shí)現(xiàn)原理以及擴(kuò)展使用,從內(nèi)存分配角度進(jìn)行了深入探究,需要的朋友可以參考下
    2015-12-12

最新評(píng)論