(C++) 树状数组

目录

一、介绍

二、一维树状数组

        2.1 区间长度

        2.2 前驱和后继

        2.3 查询前缀和

        2.4 点更新

三、一维数组的实现

        3.1 区间长度函数

        3.2 前缀和

        3.3 插入/更新

        3.4 封装成类


一、介绍

        树状数组(Binary Indexed Tree,BIT),又称为 Fenwick 树,是一种高效的数据结构,主要用于动态维护数组的前缀和(或区间和),以及支持单点更新的操作。其核心思想是利用二进制的特性,通过巧妙地设计数据结构,对每一部分设置了一个“管理员”,管理员存储量其管理对象的所和,从而实现快速的区间查询和单点更新操作。因此当需要对前n和数据进行求和的时候就不需要遍历n次,只需要查询对应管理员中的数值即可。

        本篇仅仅介绍一维的树状数组,多维的原理和此是一样的。

二、一维树状数组

        这里需要了解几个关于树状数组的几个定义。

        首先我们定义一个管理数组c[i],也就是上面提到的“管理员”。管理员的个数和一维数组的元素个数相同。

        再定义所有存储的一维数组为a[i]

        2.1 区间长度

        这里的区间长度指的是每一个管理员所管理的具体对象的多少。对于c[i],若i的二进制末尾有k个连续的0,则c[i]存储的区间长度为2^{k},即从a[i]向前数2^{k}个元素的累加和。例如,6的二级制为110,末尾有1个0,区间长度为2,就存储了a[5],a[6],即c[6] = a[5] + a[6]

        得到二进制末尾连续0的个数的方法是,将该二进制数取反后加一,再与原值做与运算。例如:20的二进制为10100,是原始二进制数,取反后为01011,加1后为01100,此时最低位的1和原数最低位的1的位置是一样的,01100和10100做与运算就得到了00100

i = 20 = 10100

\widetilde{i} = 01011        取反

01011+1=01100

01100 & 10100=00100 = 4

得到的区间长度为4。这里定义lowbit(i)函数得到的是区间的长度。

        2.2 前驱和后继

        直接的前驱为c[i-lowbit(i)]

        直接的后继为c[i+lowbit(i)]

        前驱:c[i]的直接前驱,直接前驱的直接前驱...

        后继:c[i]的直接后继,直接后继的直接后继...

        2.3 查询前缀和

        前i个元素的前缀和sum[i]等于c[i]加上c[i]的前驱。例如sum(5)c[5]加上c[5]的前驱。而c[5]的前驱为c[4],且c[4]没有前驱,故sum(5) = c[5] + c[4]

        解释一下c[5]的前驱。i=5,其二进制为0101,末尾没有0,故区间长度为1(2的0次方),则其前驱为c[5-1]=c[4],同理可得c[4]没有前驱,故只有一个前驱。

        2.4 点更新

        若对a[i]进行了修改,加上了z,则只需要更新c[i]以及后继即可,让所有的都加上z。因为该更新只会改变其本身和后继的数值,对前驱是没有影响的。

        需要注意的是,树状数组的下标需要从1开始,否则lowbit(0)=0会出现死循环。

三、一维数组的实现

        3.1 区间长度函数

        在计算机中,使用二进制的补码进行表示刚好是 i 取反加1,因此-i = \widetilde{i} + 1

int lowbit(int i)
{
	return (-i) & i;	//计算区间区间的大小
}

        3.2 前缀和

int sum(int i)
{
	int s = 0;
	for (; i > 0; i -= lowbit(i))
	{
		s += c[i];
	}
	return s;
}

        3.3 插入/更新

        该函数可以用来更新数值,也可以用来创建树状数组。只要把c[i]初始化为0,z 遍历a[i]插入即可。

void add(int i, int z)
{
	for (; i <= 9; i += lowbit(i))
	{
		c[i] += z;
	}

        3.4 封装成类

class BITree
{
private:
	std::vector<int> c;			//存储树的节点和
	int size;					//数组的大小
	int lowbit(int i);			//计算区间的大小
public:
	BITree(int n);				//输入数据量
	void Update(int i, int z);	//修改数据
	int sum(int i);			//查询
};

BITree::BITree(int n)
{
	size = n;
	c.resize(n + 1, 0);
}

int BITree::lowbit(int i)
{
	return (-i) & i;
}

void BITree::Update(int i, int z)
{
	for (; i <= 9; i += lowbit(i))
	{
		c[i] += z;
	}
}

int BITree::sum(int i)
{
	int s = 0;
	for (; i > 0; i -= lowbit(i))
	{
		s += c[i];
	}
	return s;
}

测试:

int main()
{
    int a[9] = { 1,2,3,4,5,6,7,8,9 };
    for (int i = 0; i < 9; i++)
    {
    	add(i + 1, a[i]);
    }
    std::cout << sum(9) << std::endl;

    BITree tree(9);
   for (int i = 0; i < 9; i++)
    {
	    tree.Update(i + 1, a[i]);
    }
    std::cout << tree.sum(4) << std::endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/563476.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ActiveMQ 如果数据处理出现异常会怎么样

我们有一个 Spring 的客户端&#xff0c;在处理消息的时候因为程序的原因出现消息处理异常。 对这种情况&#xff0c;ActiveMQ 会把出现异常的消息放在 DLQ 队列中进行持久化。 因此&#xff0c;在 ActiveMQ 消息处理队列中需要持续关注 DLQ 队列&#xff0c; DLQ 的队列都是无…

线段树汇总

线段树是一种二叉搜索树&#xff0c;与区间树相似&#xff0c;它将一个区间划分成一些单元区间&#xff0c;每个单元区间对应线段树中的一个叶结点。 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数&#xff0c;时间复杂度为O(logN)。而未优化的空间复杂度为2N&a…

最新版的GPT-4.5-Turbo有多强

OpenAI再次用实力证明了&#xff0c;GPT依然是AI世界最强的玩家&#xff01;在最新的AI基准测试中&#xff0c;OpenAI几天前刚刚发布的GPT-4-Turbo-2024-04-09版本&#xff0c;大幅超越了Claude3 Opus&#xff0c;重新夺回了全球第一的AI王座&#xff1a; 值得一提的是&#xf…

【机器学习】重塑汽车设计与制造:实例与代码探索

机器学习重塑汽车设计与制造 一、机器学习在汽车设计中的应用二、机器学习在智能制造与生产中的应用 在数字化浪潮的推动下&#xff0c;机器学习技术正逐步成为汽车行业的创新引擎。从概念设计到智能制造&#xff0c;机器学习正以其独特的优势助力汽车产业的革新与发展。本文将…

实现基于RAG的QA应用程序

实现基于RAG的Q&A应用程序 LLM 支持的最强大的应用程序之一是复杂的 问答 &#xff08;Q&A&#xff09; 聊天机器人。这些应用程序可以 回答有关特定来源信息的问题。这些应用程序 使用一种称为检索增强生成 &#xff08;RAG&#xff09; 的技术。 什么是检索增强生成…

Golang | Leetcode Golang题解之第43题字符串相乘

题目&#xff1a; 题解&#xff1a; func multiply(num1 string, num2 string) string {if num1 "0" || num2 "0" {return "0"}m, n : len(num1), len(num2)ansArr : make([]int, m n)for i : m - 1; i > 0; i-- {x : int(num1[i]) - 0fo…

设计模式之访问者模式(上)

访问者模式 1&#xff09;概述 1.概念 访问者模式包含访问者和被访问元素两个主要组成部分。 处方单中的各种药品信息就是被访问的元素&#xff0c;而划价人员和药房工作人员就是访问者&#xff0c;被访问的元素通常具有不同的类型&#xff0c;且不同的访问者可以对它们进行…

上位机图像处理和嵌入式模块部署(树莓派4b处理类muduo网络编程)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 既然是linux编程&#xff0c;那么自然少不了网络编程。在linux平台上面&#xff0c;有很多的网络编程库可以选择&#xff0c;大的有boost、qt&…

免费PNG素材网站推荐:设计效率倍增!

一、即时设计 新一代协同设计工具即时设计&#xff0c;内置丰富社区资源&#xff0c;可以在此获得设计前线的各类PNG图像&#xff0c;以及矢量图标&#xff0c;包括毛玻璃、3D混搭、全息投影、单色、平面化等&#xff0c;都是符合目前市场的主流风格。通过最近更新、作品、资源…

影响钕铁硼磁钢性能的因素及方法

钕铁硼永磁材料自问世以来&#xff0c;就以其优越的磁性能而备受关注&#xff0c;被称为“磁王“&#xff0c;在市场需求的不断地增长下&#xff0c;钕铁硼生产工艺及磁体性能也不断发展和提升。我们一般用剩磁、矫顽力和最大磁能积这几个指标来衡量磁性材料的磁性能。 剩磁 B…

【C++】:类和对象(上)

目录 一&#xff0c;面向过程和面向对象初步认识二&#xff0c;类的引入三&#xff0c;类的定义3.1 **类的说明**3.2 **类的访问限定符**3.3 **类的两种实现方式**3.4 **成员变量的命名规则 --- 加下划线** 四&#xff0c;类的作用域4.1 **类域的说明**4.2 **类域与命名空间域的…

分析经过j2k压缩的dicom文件经验分享

最近碰到一个问题&#xff0c;在网上搜到是用JPEG 2000压缩的DICOM文件 JPEG 2000对应的transfer syntax UID为 1.2.840.10008.1.2.4.91 参考:https://dicom.nema.org/medical/dicom/current/output/chtml/part18/sect_8.7.3.html 该文件是用专业德国老牌开发库DCMTK生成的 (…

虚拟机VMware安装与Ubuntu

1.虚拟机安装 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;2fr6 CG54H-D8D0H-H8DHY-C6X7X-N2KG6 2.Ubuntu下载 Download Ubuntu Desktop | Ubuntu 3.设置 如后续要下一些软件越大越好

Diffusion Model原理剖析

目录 前言1. DDPM演算法初览2. 图像生成模型共同目标3. VAE: Lower bound of l o g P ( x ) logP(x) logP(x)4. Diffusion Model背后的数学原理5. 为什么需要Sample?6. Diffusion Model的应用7. Diffusion Model成功的关键总结参考 前言 接着上篇文章 图像生成模型浅析&#…

15.C++常用的算法_拷贝和替换算法

文章目录 遍历算法1. copy()代码工程运行结果 2. replace()代码工程运行结果 3. replace_if()代码工程运行结果 4. swap()代码工程运行结果 遍历算法 1. copy() 代码工程 copy()函数不要因为使用而使用#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include&l…

dremio支持设置

Dremio 支持提供可用于诊断目的的设置。这些设置通过 Dremio UI&#xff1a;设置>支持启用&#xff08;或禁用&#xff09; 使用 Client Tools 可以配置当用户查看数据集中的数据时&#xff0c;Dremio 项目的工具栏上显示哪些客户端应用程序按钮。用户可以通过单击相应的工具…

免费ssl泛域名/泛解析证书获取教程

泛域名SSL证书&#xff0c;也称为通配符证书&#xff0c;它可以保护一个主域名下的所有子域名。这意味着&#xff0c;无论你有多少个子域名&#xff0c;只要安装了一个泛域名SSL证书&#xff0c;就可以实现全部子域名的安全保护。这种证书非常适合大型企业或有大量子域名的网站…

数电复习(五)半导体存储电路

半导体存储电路 5.1 概述5.2 SR锁存器5.3 触发器5.3.1电平触发的触发器5.3.2 边沿触发器5.3.3 脉冲触发(主从) 触发器5.3.4 触发器逻辑功能的转换 5.4 寄存器5.4.1 数码寄存器5.4.2 移位寄存器 5.5 存储器5.5.1 ROM5.5.2 随机存储器RAM5.5.3 存储器容量的扩展5.5.4 用存储器实现…

怎么申请免费SSL证书,如何安装

什么是SSL证书&#xff0c;SSL&#xff0c;即Secure Sockets Layer&#xff08;安全套接层&#xff09;&#xff0c;它是一种安全协议&#xff0c;用于在互联网通信中为数据提供加密保护&#xff0c;从而防止数据被窃听或篡改。而SSL证书则是由权威的数字证书认证机构&#xff…

数据结构面试常见问题:什么是哈希表?它的工作原理是什么?

哈希表的基本概念 在我们的日常生活中&#xff0c;我们经常需要存储和查找各种信息&#xff0c;这些信息可能是电话号码&#xff0c;地址&#xff0c;或者是商品的价格等等。这些信息的存储和查找&#xff0c;就像是我们在一个巨大的仓库中存放和寻找物品。这个仓库就是数据结…
最新文章