面试题:自定义聚类函数

定义一个聚类函数 cluster(int data[], int len, int radius);
data中的值没有重复,长度为len,
把按照数值的聚类进行分为n组,
对于组G中任意一个数值a,总是能在本组G中找到一个数值b, 使 |a-b| < radius  .
在函数内部打印出所有n个组成员,分成n行输出

(要求:不能使用数组排序操作)

例如:
   输入 data[] = { 1, 20, 89, 22, 72, 2,39, 3,56,86, 5, 93,13, 15, 18, 73, 79, 81, 25, 38, 43, 83,48, 52, 59,92,84,95,87 };
   正确的屏幕输出为组及成员为(每行为一组,行之间顺序随意,组内成员顺序随意):
   1, 2, 3, 5,
   13, 15, 18, 20, 22, 25,
   39, 38, 43, 48, 52, 56, 59,
   73, 72,
   79, 89, 92, 84, 95,87,86, 93,81, 83,

思路:遍历一遍数组,每来一个新的元素,就判断该元素是否在已经存在的组里,这里每个组是一个聚类。如果哦不存在任意一个聚类,则新建一个聚类,否则将 * 所有包含该数字的聚类再合并。

typedef pair<vector<int>,pair<int,int>> grouptype;

bool isInThisGroup(const int radius, const int num, grouptype& group) {
  int min = group.second.first;
  int max = group.second.second;
  if (num >= min - radius && num <= max + radius)
    return true;
  return false;
}

void mergegroup(grouptype& g1,grouptype& g2) {
  int min1 = g1.second.first;
  int max1 = g1.second.second;
  int min2 = g2.second.first;
  int max2 = g2.second.second;

  int min = min1 < min2 ? min1 : min2;
  int max = max1 > max2 ? max1 : max2;

  auto& g1_v = g1.first;
  auto& g2_v = g2.first;
  for(auto e : g2_v)
    g1_v.push_back(e);
  g1.second.first = min;
  g1.second.second = max;
}

void updateEdge(grouptype& g, int num) {
  if (num < g.second.first)
    g.second.first = num;
  if (num > g.second.second)
    g.second.second = num;
}

void cluster(int data[], int len, int radius)
{
  if (len < 1)
    return;

  vector<grouptype> res;
  for (int i = 0; i < len; ++i) {
    int cu = data[i];
    // 遍历数组
    vector<int> inGroup;
    for (int j = 0; j < res.size(); ++j) {
      // 遍历当前组,判断当前数字是否可以聚类到某个组里
      if (isInThisGroup(radius, data[i], res[j])) {//如果当前数字在该组内
        inGroup.push_back(j);
      }
    }

    // 处理组的合并
    if (inGroup.size() == 0) { // 当前数字不在已经存在的任意一组
      // 新建组
      vector<int> tempgroup;
      tempgroup.push_back(data[i]);
      res.push_back(grouptype(tempgroup, std::make_pair(data[i],data[i])));
    } else if (inGroup.size() == 1) {
      // 只需要更新组边界,不需要合并
      res[inGroup[0]].first.push_back(data[i]);
      updateEdge(res[inGroup[0]], data[i]);
    } else if (inGroup.size() > 1) {
      // 需要合并组,并且更新最终合并组的边界
      for (int k = 1; k < inGroup.size(); ++k) {
        mergegroup(res[inGroup[0]], res[inGroup[k]]);
      }
      res[inGroup[0]].first.push_back(data[i]);
      updateEdge(res[inGroup[0]], data[i]);
      // 从原来的结果总删除已经合并的组
      for (int k = 1; k < inGroup.size(); ++k) {
        res[inGroup[k]] = res.back();
        res.pop_back();
      }
    }
  }

  // 打印最终结果
  for(auto& e : res) {
    for (auto& el : e.first) {
      cout << el << ',';
    }
    cout << endl;
  }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值