js实现凸包问题

背景:

地图上给出若干个点,求出这些点围绕的最大面积,并按顺序排列。

原理:
暴力枚举,由反证法得x轴最小的值一定是围绕的边界点,将其作为起点,在寻找下一个点符合其余的点均在这两个点构成直线的一侧。最后回到初始点时返回。

向量和点关系算法:

S(P1,P2,P3)=|y1 y2 y3|= (x1-x3)*(y2-y3)-(y1-y3)*(x2-x3)

当P1P2P3逆时针时S为正的,当P1P2P3顺时针时S为负的。

因为坐标经度需求大,为了精确计算使用了函数实现四则运算。

function mul(a, b) {
  var c = 0,
    d = a.toString(),
    e = b.toString();
  try {
    c += d.split(".")[1].length;
  } catch (f) {}
  try {
    c += e.split(".")[1].length;
  } catch (f) {}
  return (
    (Number(d.replace(".", "")) * Number(e.replace(".", ""))) / Math.pow(10, c)
  );
}
function sub(a, b) {
  var c, d, e;
  try {
    c = a.toString().split(".")[1].length;
  } catch (f) {
    c = 0;
  }
  try {
    d = b.toString().split(".")[1].length;
  } catch (f) {
    d = 0;
  }
  return (e = Math.pow(10, Math.max(c, d))), (mul(a, e) - mul(b, e)) / e;
}

输入数据结构示例:
lines[{x:"123",y:"456"},{x:"123",y:"456"}]

具体实现:

 //范围算法
    ConvexHull(lines) {
      //排序去重
      for (let i = 0; i < lines.length; i++) {
        for (let j = 0; j < lines.length - i - 1; j++) {
          if (lines[j].x > lines[j + 1].x) {
            let tamp = lines[j];
            lines[j] = lines[j + 1];
            lines[j + 1] = tamp;
          }
          if (lines[j].x == lines[j + 1].x && lines[j].y == lines[j + 1].y) {
            lines.splice(j + 1, 1);
            j--;
          }
        }
      }
      let result = [];
      let index = 1;
      result.push(lines[0]);
      while (true) {
        let point = this.findNext(lines, result[index - 2], result[index - 1]);
        if (point == null) break;
        result.push(point);
        if (point.x == lines[0].x && point.y == lines[0].y) {
          break;
        }
        if (index > lines.length + 2) {
          break;
        }
        index++;
      }
      return result;
    },
   findNext(lines, start, node) {
      for (let i = 0; i < lines.length; i++) {
        if (start != null && start.x == lines[i].x && start.y == lines[i].y) {
          continue;
        }
        if (node != null && node.x == lines[i].x && node.y == lines[i].y) {
          continue;
        }
        let search = true;
        let target = -9999;
        for (let j = 0; j < lines.length; j++) {
          if (i == j) continue;
          if (node != null && node.x == lines[j].x && node.y == lines[j].y) {
            continue;
          }
          let left =
            sub(node.x, lines[j].x) * sub(lines[i].y, lines[j].y) -
              sub(node.y, lines[j].y) * sub(lines[i].x, lines[j].x) >
            0
              ? true
              : false;
          if (target == -9999) {
            target = left;
          }
          if (left != target) {
            search = false;
            break;
          }
        }
        if (search == true) {
          return lines[i];
        }
      }
    },

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值