基本线段树

前言

作为一个常用的数据结构,线段树怎能不与玄学扯上关系。所以今天要讲的是:玄学。

基本概念

所谓线段树,就是将一个线段用数轴上的一个点表示。
但是我当初就没搞懂,所以我决定用我能理解的方法来讲。
想象有一条线,嗯对,一条线段。
将这条线段从中点分开,中点归左边。
就这样递归,递归,递归。
直到线段长度为1时,return;
好,这就是建树的过程。
那你肯定要问,凭什么要这样写。
别急,下面为你详细解答。


以下为重点部分:
我们都知道,数轴上的区间覆盖处理一直是个巨坑,一个不小心就超时。
所以我们想出了线段树这种辅助结构。
我们要找一个长度为1的线段时,如果用线段树,时间复杂度会是多少呢?
答案是:

O(logn)O(log⁡n)

我们来分析一下:
每一次递归后,待查询线段的长度就成了父亲线段长度的½
所以线段树真的是一个很高效的数据结构(某些情况下)


实现

声明:全部代码将用C++语言完成

我们用结构体来存储这棵树

struct node{
    int l,r;
}tree[6*MAXN+5];

不知为何,我用4*MAXN时总会RE

先来建树部分的代码

void Build(int number,int left,int right){
    tree[number].l=left;
    tree[number].r=right;
    if(l==r)  //长度为1时
        return;
    int mid=(l+r)/2;
    Build(number*2,left,mid);   //建左子树
    Build(number*2+1,mid+1,right);  //建右子树
}

然后是查找部分

void Find(int number,int left,int right){
    if(tree[number].l==left&&tree[number].r==right){  //如果找到了的话
        printf("Find it!");
        return;
    }
    .
    .
    .
    // 这里并不是我偷懒,而是有问题要讨论
}

在这里我们发现了一个问题——有两种实现方式,分别是:

  1. 严谨认真,将左右端点依次与中点进行比较。
  2. 不管了,直接上,到时候不行再倒回来。

那么大家觉得哪个是对的呢?猜一猜


选1的请举手,恭喜你,你是对的
但是,它们两个都是对的,时间复杂度也没有什么区别。
而且2码起来还要简单一些。
所以说。。。

选2的请举手
原来你是大佬啊。虽然可能是蒙的


所以说,讲了一大通废话,也是时候该上代码了。
我也准备了两种代码,随大家喜好咯

方法1:

void Find(int number,int left,int right){
    if(tree[number].l==left&&tree[number].r==right)  
        return 1;
    int mid=(tree[number].l+tree[number].r)/2;
    if(r<=mid) 
        return Find(number*2,left,right);
    else if(l>mid)
        return Find(number*2+1,left,right);
    else return max(Find(number*2,left,mid),Find(number*2+1,mid+1,right));
}

方法2:

void Find(int number,int left,int right){
    if(tree[number].l==left&&tree[number].r==right)  
        return 1;
    if(tree[number].l>right||tree[number].r<left)
        return 0;
    int mid=(tree[number].l+tree[number].r)/2;
    return max(Find(number*2,left,mid),Find(number*2+1,mid+1,right));
}

未完待续。。。
请关注下一篇进击的线段树——RMQ

转载于:https://www.cnblogs.com/SteinGate/p/9337441.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值