1.“树状数组”数据结构的一种应用

对含有n个元素的数组(a[1],...,a[k],...,a[n]):

(1)求出第i个到第j个元素的和,sum=a[i]+...+a[j]。

进行j-i+1次加法,复杂度为O(j-i+1)

(2)任意修改其中某个元素的值。

使用数组下标可以直接定位修改,时间复杂度为O(1)

对于同时支持上述两种操作的系统中,求和操作(1)求任意连续个数组元素和的平均时间复杂度为O(n),修改操作(2)时间复杂度是O(1)。如果系统中大量进行上述两种操作m次,其中执行操作(1)概率1/p,操作(2)概率1-1/p,则系统时间复杂度为:

可以使用树状数组使得上述两种操作的时间复杂度为O(m*logn)。

2.树状数组介绍

核心思想:

(1)树状数组中的每个元素是原数组中一个或者多个连续元素的和。

(2)在进行连续求和操作a[1]+...+a[n]时,只需要将树状数组中某几个元素的和即可。时间复杂度为O(lgn)

(3)在进行修改某个元素a[i]时,只需要修改树状数组中某几个元素的和即可。时间复杂度为O(lgn)

下图就是一个树状数组的示意图:

解释如下:

1) a[]: 保存原始数据的数组。(操作(1)求其中连续多个数的和,操作(2)任意修改其中一个元素)

e[]: 树状数组,其中的任意一个元素e[i]可能是一个或者多个a数组中元素的和。如e[2]=a[1]+a[2]; e[3]=a[3]; e[4]=a[1]+a[2]+a[3]+a[4]。

2) e[i]是几个a数组中的元素的和?

如果数字 i 的二进制表示中末尾有k个连续的0,则e[i]是a数组中2^k个元素的和,则e[i]=a[i-2^k+1]+a[i-2^k+2]+...+a[i-1]+a[i]。

如:4=100(2)  e[4]=a[1]+a[2]+a[3]+a[4];

6=110(2)  e[6]=a[5]+a[6]

7=111(2)  e[7]=a[7]

3) 后继:可以理解为节点的父亲节点。是离它最近的,且编号末位连续0比它多的就是它的父亲,如e[2]是e[1]的后继;e[4]是e[2]的后继。

如e[4] = e[2]+e[3]+a[4]= a[1]+a[2]+a[3]+a[4] ,e[2]、e[3]的后继就是e[4]。

后继主要是用来计算e数组,将当前已经计算出的e[i]添加到他们后继中。

前驱:节点前驱的编号即为比自己小的,最近的,最末连续0比自己多的节点。如e[7]的前驱是e[6],e[6]的前驱是e[4]。

前驱主要是在计算连续和时,避免重复添加元素。

如:Sum(7)=a[1]+...+a[7]=e[7]+e[6]+e[4]。(e[7]的前驱是e[6], e[6]的前驱是e[4])

计算前驱与后继:

lowbit(i) = ( (i-1) ^ i) & i ;

节点e[i]的前驱为 e[ i - lowbit(i) ];

节点e[i]的前驱为 e[ i + lowbit(i) ]

3.树状数组代码示例

1 #include

2 #include

3

4 using namespacestd;5

6 int input(int*,int*,int); ///输入数据

7 int calStageSum(int*,int); ///计算树状数组

8 int getSum(int*,int); ///求出前n个数字的和

9 int updataElement(int*,int*,int,int,int); ///更新某一位置上的元素

10

11 intmain (){12 intn;13 intnewValue;14 cout<3) :";15 cin>>n;16

17 int *num = new int[n+1];18 int *sum = new int[n+1];19

20 cout<

24 cout<

26 cout<>newValue;28 updataElement(sum,num,n,2,newValue);29

30 cout<

32 delete []num;33 delete []sum;34 return 0;35 }36

37 int input(int* num,int *sum,intn){38 for(int i=1;i<=n;i++){39 cin>>num[i];40 sum[i] =num[i];41 }42 return 0;43 }44

45 int calStageSum(int *sum,intn){46 intlowbit;47 intpar;48 for(int i=1;i<=n;i++){49 lowbit = ((i-1)^i)&i;50 par = lowbit+i; ///后继节点id

51 if(par <=n){52 sum[par] = sum[par] +sum[i];53 }54 }55 return 0;56 }57

58 int getSum(int* sum,intn){59 int sumPreN = 0;60 int lowbit = 0;61 while(n!=0){62 sumPreN +=sum[n];63 lowbit = ((n-1)^n)&n;64 n = n - lowbit; ///前驱节点id

65 }66 returnsumPreN;67 }68

69 int updataElement(int* sum,int *num,int n,int pos,intnewvalue){70 int lowbit = 0;71 int dis = newvalue -num[pos];72 num[pos] =newvalue;73 sum[pos] = sum[pos]+dis;74

75 while(true){76 lowbit = ((pos-1)^pos)&pos;77 pos = pos + lowbit; ///后继节点id

78 if(pos <=n){79 sum[pos] = sum[pos]+dis;80 }81 else

82 break;83 }84 return 0;85 }

View Code

python 树状数组_树状数组(Binary Indexed Tree) 总结相关推荐

  1. js 数组 实现 完全树_算法和数据结构 | 树状数组(Binary Indexed Tree)

    本文来源于力扣圈子,作者:胡小旭.点击查看原文 力扣​leetcode-cn.com 树状数组或二叉索引树(英语:Binary Indexed Tree),又以其发明者命名为 Fenwick 树.其初 ...

  2. 树状数组 Binary Indexed Tree (B.I.T)

    树状数组 算法训练营 树状数组 (Binary Indexed Tree(B.I.T), Fenwick Tree) 是一个查询和修改复杂度都为 log(n) 的数据结构. 「前缀和查询」与「单点更新 ...

  3. C# 传递数组参数_一维数组_二维数组

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  4. 树状数组 Binary Indexed Tree/Fenwick Tree

    2018-03-25 17:29:29 树状数组是一个比较小众的数据结构,主要应用领域是快速的对mutable array进行区间求和. 对于一般的一维情况下的区间和问题,一般有以下两种解法: 1)D ...

  5. python如何提取奇数_如何在数组中只获取奇数并使用numpy for python将其平方?

    numpy的强大之处在于它允许您在单个操作中对整个数组进行操作.这称为矢量化或矢量化.当然,在幕后也有这样做的循环,但它们是用C语言编写的,并且经过高度优化,因此它们的运行速度比纯python所能达到 ...

  6. python初始化一个二维数组_二维数组初始化

    对于一个M行N列的二维数组,可以看成是M行一维数组,一维数组是N列.例如 int array[3][2]; 是一个3行2列的二维数组,其实,如同3个一维数组,一维数组是2列.那么,对3行2列的二维数组 ...

  7. python定义二维数组_二维数组的定义、初始化和输出,C语言二维数组详解

    本节学习二维数组.二维数组与一维数组相似,但是用法上要比一维数组复杂一点.后面的编程中,二维数组用得很少,因为二维数组的本质就是一维数组,只不过形式上是二维的.能用二维数组解决的问题用一维数组也能解决 ...

  8. 创建数组_如何创建数组

    js数组 js的数组不是典型的数组 典型的数组 元素的数据类型相同 使用连续的内存储存 通过数字下标获取元素 但是js的数组不这样 元素的数据类型可以不同 内存不一定连续的(对象是随机储存的) 不可以 ...

  9. c++ 构造函数数组_从 JS 数组操作到 V8 array.js

    前言 最近在写面试编程题,经常用到数组,经常想偷个懒,用它提供的方法,奈何还是对数组方法使用不熟练,导致写了很多的垃圾代码,很多地方稍加修改的话肯定变得简洁高效优雅? 所以✍这篇文章本着了解一下Jav ...

  10. 研一寒假02-指针_new分配内存_使用new来创建动态数组_使用动态数组_使用delete来释放new分配的内存...

    #---------------------------------指针-----------------------------------# #include <iostream> i ...

最新文章

  1. 2020 年 5 月程序员工资统计,平均 14542 元,我又拖后腿了!
  2. Mongodb 添加删除分片与非分片表维护
  3. android 隐藏闹钟通知,redis环境搭建
  4. [题解]CQOI2012 T2 组装 assemble
  5. android 开发art,Android应用开发之Android 系统启动原理(art 虚拟机)
  6. 数据在市场运营中的应用
  7. [大牛就是牛]双栈排序
  8. 数据库流行度11月排行榜:Oracle 意外滑落和 PostgreSQL 再创新高
  9. 随机调用mysql数据库表值10条php_PHP随机显示mysql数据库中的数据
  10. 协程 eventlet
  11. 洛谷2657 windy数(数位DP)
  12. 【ACL2020-CMU-Google】MobileBERT:用于资源受限设备的任务无关“瘦版”BERT
  13. Centos安装php高版本
  14. AMD IOMMU与Linux (2) -- IVRS及AMD IOMMU硬件初始化
  15. 智伴机器人传销_智伴机器人是传销吗?
  16. 搜狗输入法劝退换成了谷歌拼音
  17. 大型架构学习——美团猫眼模块化实践
  18. Pytorch求向量的L1范数或L2范数
  19. 如何清除电脑桌面图标蓝底
  20. 修改迅雷下载链接的方法。

热门文章

  1. Vue项目打包移动端App(App打包教程),简便直接
  2. java毕业生设计采购物料质量检验系统计算机源码+系统+mysql+调试部署+lw
  3. javascript 保留小数点后2位
  4. 双频WiFi手机的网速为何那么快?看完这篇你就懂了
  5. 触控科技Cocos2d-x游戏引擎的重量
  6. 解决Ignoring InnerClasses attribute for an anonymous inner class编译是出现的警告
  7. mysql数据库 中文乱码_数据库 MySQL中文乱码解决办法总结
  8. phonetic symbol
  9. 喵的Unity游戏开发之路 - 复杂重力
  10. apple账号和icloud邮箱的关系