树状数组 线段树 模板

树状数组和线段树都是对于一个区间查询和修改的时间复杂度比较低(log(n))的数据结构,主要用于查询任意两位之间的所有元素之和。
树状数组和线段树很像,但能用树状数组解决的问题,基本上都能用线段树解决,而线段树能解决的树状数组不一定能解决。相比较而言,树状数组效率要高很多。
树状数组

生成树状数组
设a[1…N]为原数组,定义c[1…N]为对应的树状数组:
c[i] = a[i - 2^k + 1] + a[i - 2^k + 2] + … + a[i]
其中k为i的二进制表示末尾0的个数,所以2^k即为i的二进制表示的最后一个1的权值.
所以2^k可以表示为n&(n^(n-1))或更简单的n&(-n).

int lowbit(int n)  
{  
    return n& (-n);    
        // return n&(n^(n-1));  
}  

也就是说,把k表示成二进制1***10000,那么c[k]就是1***00001 + 1***00010 + … + 1***10000这一段数的和。
举例:
这里写图片描述
可以看出:设节点编号为x,那么这个节点管辖的区间为2^k个元素。(其中k为x二进制末尾0的个数)
C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8

C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
修改
修改一个节点,必须修改其所有祖先,最坏情况下为修改第一个元素,最多有log(n)的祖先。
对a[n]进行修改后,需要相应的修改c数组中的p1, p2, p3…等一系列元素
其中p1 = n, pi+1 = pi + lowbit(pi)
所以修改原数组中的第n个元素可以实现为:

void Modify(int n, int delta)  
{  
    while(n <= N)  
    {   
        c[n] += delta;   
        n += lowbit(n);  
    }  
}  

求和
当要查询a[1],a[2]…a[n]的元素之和时,需要累加c数组中的q1, q2, q3…等一系列元素
其中q1 = n,qi+1 = qi - lowbit(qi)
所以计算a[1] + a[2] + .. a[n]可以实现为:

int Sum(int n)  
{  
    int result = 0;  
    while(n != 0)  
    {   
        result += c[n];   
        n -= lowbit(n);   
    }  
    return result;  
}  

总的来说
若需改变a[i],则c[i]、c[i+lowbit(i)]、c[i+lowbit(i)+lowbit(i+lowbit(i)]……就是需要改变的 c数组中的元素。
若需查询s[i],则c[i]、c[i-lowbit(i)]、c[i-lowbit(i)-lowbit(i- lowbit(i))]……就是需要累加的c数组中的元素。

线段树
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)
写的超级详细的一个线段树专题
直接贴模板
建立树

void build(int l,int r,int k)
{
    if(l==r)
    {
        scanf("%d",&num[k]);
        return ;
    }
    int mid=(l+r)/2;
    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
    num[k]=max(num[k*2],num[k*2+1]);
}

更新节点

void update(int i,int date,int l,int r,int k)
{
    if(l==r)
    {
        num[k]=date;
        return ;
    }
    int mid=(l+r)/2;
    if(i<=mid)
    update(i,date,l,mid,k*2);
    else
    update(i,date,mid+1,r,k*2+1);
    num[k]=max(num[k*2],num[k*2+1]);
}

区间更新

void Change(node *p, int a, int b) /* 当前考察结点为p,修改区间为(a,b]*/  

{  

  if (a <= p->Left && p->Right <= b)  

  /* 如果当前结点的区间包含在修改区间内*/  

  {  

     ...... /* 修改当前结点的信息,并标上标记*/  

     return;  

  }  

  Push_Down(p); /* 把当前结点的标记向下传递*/  

  int mid = (p->Left + p->Right) / 2; /* 计算左右子结点的分隔点 

  if (a < mid) Change(p->Lch, a, b); /* 和左孩子有交集,考察左子结点*/  

  if (b > mid) Change(p->Rch, a, b); /* 和右孩子有交集,考察右子结点*/  

  Update(p); /* 维护当前结点的信息(因为其子结点的信息可能有更改)*/  

}  

区间查询

int query(int node, int begin, int end, int left, int right)    
{   
    int p1, p2;    

    /*  查询区间和要求的区间没有交集  */  
    if (left > end || right < begin)    
        return -1;    

    /*  if the current interval is included in  */    
    /*  the query interval return segTree[node]  */  
    if (begin >= left && end <= right)    
        return segTree[node];    

    /*  compute the minimum position in the  */  
    /*  left and right part of the interval  */   
    p1 = query(2 * node, begin, (begin + end) / 2, left, right);   
    p2 = query(2 * node + 1, (begin + end) / 2 + 1, end, left, right);    

    /*  return the expect value  */   
    if (p1 == -1)    
        return p2;    
    if (p2 == -1)    
        return p1;    
    if (p1 <= p2)    
        return  p1;    
    return  p2;      

举例区间最大值查询

int query(int L,int R,int l,int r,int k)
{
    if(L<=l&&R>=r)
    {
        return num[k];
    }
    int mid=(l+r)/2;
    int ans=0;
    if(L<=mid)
    ans=max(ans,query(L,R,l,mid,k*2));
    if(R>mid)
    ans=max(ans,query(L,R,mid+1,r,k*2+1));
    return ans;
}
内容概要:本文详细介绍了如何利用Simulink进行自动代码生成,在STM32平台上实现带57次谐波抑制功能的霍尔场定向控制(FOC)。首先,文章讲解了所需的软件环境准备,包括MATLAB/Simulink及其硬件支持包的安装。接着,阐述了构建永磁同步电机(PMSM)霍尔FOC控制模型的具体步骤,涵盖电机模型、坐标变换模块(如Clark和Park变换)、PI调节器、SVPWM模块以及用于抑制特定谐波的陷波器的设计。随后,描述了硬件目标配置、代码生成过程中的注意事项,以及生成后的C代码结构。此外,还讨论了霍尔传感器的位置估算、谐波补偿器的实现细节、ADC配置技巧、PWM死区时间和换相逻辑的优化。最后,分享了一些实用的工程集成经验,并推荐了几篇有助于深入了解相关技术和优化控制效果的研究论文。 适合人群:从事电机控制系统开发的技术人员,尤其是那些希望掌握基于Simulink的自动代码生成技术,以提高开发效率和控制精度的专业人士。 使用场景及目标:适用于需要精确控制永磁同步电机的应用场合,特别是在面对高次谐波干扰导致的电流波形失真问题时。通过采用文中提供的解决方案,可以显著改善系统的稳定性和性能,降低噪声水平,提升用户体验。 其他说明:文中不仅提供了详细的理论解释和技术指导,还包括了许多实践经验教训,如霍尔传感器处理、谐波抑制策略的选择、代码生成配置等方面的实际案例。这对于初学者来说是非常宝贵的参考资料。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值