如何在一组线段中找出交叉的部分

//如何在一组线段中快速找到有重叠的部分
var crossResult = (function getCrossInterval(intervalArray){
    var result = [];
    var tree = [];
    //将所有线段写到树中,这里用数组处理免去了排序的步骤,以线段的最小值作为key避免了组内比较因为都是包含关系,以线段长度作为key是为了方便比较出结果后取出相应数据
    intervalArray.forEach(function(v,k){
        var length = v[1] - v[0],item;
        !tree[v[0]] ? item = [] : item = tree[v[0]];
        item[length] = v; 
        tree[v[0]] = item;
    });
    //获取树中的key
    var keys = [];
    tree.forEach(function(v,k){
        keys.push(k);
    });
    //计算key的个数
    var treeLength = keys.length;
    //最外层循环到n-1为止因为最后一组线段不需要主动和别人比较
    first:for(var i = 0;i < treeLength - 1;i++){
        var sub = tree[keys[i]];
        var subKeys = [];
        sub.forEach(function(item,index){
            subKeys.push(index);
        });
        var subLength = subKeys.length;
        //循环叶子节点,取每一个线段和其他组的线段比较
        second:for(var j = 0;j < subLength;j++){
            //被比较的循环从i+1开始 不需要查找以前的数据
            thred:for(var k = i + 1;k < treeLength;k++){
                //获取被比较线段数组的最小值(对应的key值)
                var comparedMin = keys[k];
                //获取被比较线段组
                var comparedSub = tree[comparedMin];
                //计算被比较数组的长度
                var comparedSubLength = comparedSub.length;
                if(sub[subKeys[j]][1] < comparedMin){
                    //如果被比较线段的最小值大于比较线段的最大值说明没有落在比较线段的区间中,以后的数据都不用比较了,因为是升序排列,所以直接跳到最外层循环
                    continue second;
                }else if(sub[subKeys[j]][1] == comparedMin){
                    //如果被比较线段的最小值等于比较线段的最大值说明两个区间只有一个交叉点,取出这组所有的数据,作为结果,以后的数据都不用比较了,因为是升序排列,所以直接跳到最外层循环
                    comparedSub.forEach(function(v1,k1){
                        var combine = [sub[subKeys[j]],v1];
                        result.push(JSON.stringify(combine));
                    });
                    continue second;
                }else{
                    //如果被比较线段的最小值小于比较线段的最大值说明该线段的最小值落在了比较线段区间中,需要计算最大值是否在区间外,才能形成交叉
                    //如果要最大值落在区间外,被比较线段的最大值的最小取值应该是比较线段的最大值+1
                    var min = sub[subKeys[j]][1] + 1;
                    //形成交叉的最小长度
                    var minLength = min - comparedMin;
                    //循环被比较数组,找出长度大于等于minLength的元素即为可与比较数组形成交叉的线段
                    var crossArray = comparedSub.filter(function(v2,k2){
                        return k2 >= minLength;
                    });
                    crossArray.forEach(function(v3,k3){
                        var combine = [sub[subKeys[j]],v3];
                        result.push(JSON.stringify(combine));
                    });
                }
            }
        }
    }
    return result;
})([
    [2,5],
    [3,7],
    [3,6],
    [5,8],
    [2,7],
    [1,3],
    [4,7],
    [2,9],
    [1,6],
    [1,5],
    [3,9],
    [2,8],
    [2,9],
    [3,11],
    [1,8],
    [4,6]
]);
console.log(crossResult);

 

转载于:https://my.oschina.net/u/3103453/blog/3017769

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值