线段树-入门




/**
* 线段树入门
* 问题:已知线段[2,5] [4,6] [0,7];求点2,4,7分别出现了多少次
* 以下代码建立的线段树用链表来保存,且树的叶子结点类似[i,i]
*
* 参考链接:http://hi.baidu.com/semluhiigubbqvq/item/be736a33a8864789f4e4ad18
* @author lijinnan
*/
public class SegmentTreeLearn {

public static void main(String[] args) {
SegmentTree tree = new SegmentTree(0, 7);
int[][] segments = {
{2, 5},
{4, 6},
{0, 7}
};
int[] targets = {2, 4, 7};
for (int i = 0, len = segments.length; i < len; i++) {
int[] segment = segments[i];
tree.insert(segment[0], segment[1]);
}
for(int target : targets) {
System.out.println(target + ":" + tree.caculateExistingTimes(target));
}
}



}

class SegmentTree {

//递归定义的,因此很多操作都是递归实现
private class Segment {
int left;
int right;
int count;
Segment leftChild;
Segment rightChild;
}

private Segment root;

public SegmentTree (int left, int right) {
root = new Segment();
build(root, left, right);
}

public void insert(int left, int right) {
insert(root, left, right);
}

public int caculateExistingTimes(int target) {
return caculateExistingTimes(root, target);
}

//从根节点开始查找叶子结点[target, target],对经过的节点的count求和
private int caculateExistingTimes(Segment root, int target) {
int result = 0;
while( root.left != root.right) {
int rootMid = root.left + (root.right - root.left) / 2;
result += root.count;
if (target <= rootMid) {
root = root.leftChild;
} else if (target > rootMid) {
root = root.rightChild;
}
}
return result;
}

private void build(Segment root, int left, int right) {
root.left = left;
root.right = right;
if (left != right) {
int mid = left + (right - left) / 2;
root.leftChild = new Segment();
root.rightChild = new Segment();
build(root.leftChild, left, mid);
build(root.rightChild, mid + 1, right);
}
}

private void insert(Segment root, int left, int right) {

int rootLeft = root.left;
int rootRight = root.right;
int rootMid = rootLeft + (rootRight - rootLeft) / 2;

//匹配,出现次数加1
if (left == rootLeft && right == rootRight) {
root.count++;
return;
}

if (right <= rootMid) {
insert(root.leftChild, left, right);
} else if (left > rootMid){
insert(root.rightChild, left, right);
} else {
insert(root.leftChild, left, rootMid);
insert(root.rightChild, rootMid + 1, right);
}
}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值