ProDeveloperTutorial.com

教程和编程解决方案
菜单
  • Shell脚本
  • 系统设计
  • Linux系统编程
  • 4g LTE
  • 编码问题
  • C
  • C ++
  • DSA
  • GIT

树数据结构教程14. Fenwick树及其实现

前开发者教程 2019年8月18日

Fenwick树或二进制索引树的简介。

 

在本教程中,我们将倾向于

  1. 获取范围总和
  2. 更新范围

通过使用芬威克树。

 

Problem Statement:

Given an array you need to find the sum of ranges.

 

树数据结构教程14. Fenwick树及其实现

 

我们需要找到范围[0 – 3]的总和。

2 + 3 + 1 + 5 = 11。

使用暴力破解方法的简单方法。即将所有元素从开始索引添加到结束索引。

这将花费线性时间。

 

还有其他方法可以解决此问题吗?

是的,采用另一个数组,您可以在其中存储先前索引元素的总和。

 

例如:

 

树数据结构教程14. Fenwick树及其实现

 

但是这里有一个问题。如果您更新索引2的值以将其添加“ 1”怎么办?

 

然后您需要在索引2之后的所有元素中添加“ 1”

树数据结构教程14. Fenwick树及其实现

 

但是,如果您在索引“ 0”处进行更新,则将花费O(n)时间来更新所有值。

 

还有其他有效的解决方法吗?

 

是的,我们可以使用分域树。

 

Fenwick树基于所有数字都可以由2 ^ n表示的事实。因此,算法将利用此优势使查询速度更快。

 

我们将借助一个例子来理解Fenwick树。

 

Fenwick树将对2个操作有用。这些操作我们也将在本章中看到。

 

  1. 给定范围时计算总和
  2. 在给定索引的元素上添加值

 

考虑具有14个元素的数组,如下所示:

 

树数据结构教程14. Fenwick树及其实现

 

  1. 给定范围时计算总和

 

例如,我们需要找到sum(13)。

如上所述,任何数字都可以用2的幂表示。

 

13可以写成2 ^ 3 + 2 ^ 2 + 2 ^ 0

 

13 =范围[1,8] +范围[9,12] +范围[13,13]

= 40 + 22 + 1

= 63

 

因此,我们要做的是预先计算这些范围。因此,当我们获得一个范围来计算总和时,我们首先需要添加这些预先计算的值。

 

如何预先计算值?

我们计算2的幂的范围。

因此范围将是1、2、4、8、16、32…

 

在第一层的示例中,可以如下计算

 

树数据结构教程14. Fenwick树及其实现

 

如上图所示,我们可以推断出以下3点:

 

  1. 我们正在基于2的幂计算范围。
  2. 在计算范围值时,存在差距
  3. 我们停在2 ^ 3。因为2 ^ 4是16,所以不在我们数组的范围内。

 

因此,我们计算了级别0。下一个是级别1,我们从间隙开始计算了同样的级别。

 

在此之前,让我们标记我们计算出的值的索引。

树数据结构教程14. Fenwick树及其实现

 

在填补空白的同时,我们需要考虑连续的空白。

 

从图像中,索引[3,3]仅具有1个间隙。因此,我们计算2 ^ 0 = 1。

树数据结构教程14. Fenwick树及其实现

间隙再次从索引[5]开始,它具有连续的3个间隙。因此我们计算2 ^ 0,2 ^ 1。我们不需要计算2 ^ 2,因为它的长度是4,并且我们的间隔也没有那么长。因此,我们把它留在那里。

 

树数据结构教程14. Fenwick树及其实现

 

现在我们看一下索引[7,7],因为它只有1个间隙,所以我们仅计算2 ^ 0。

 

下一个间隔是从索引9到14。在这里,我们再次计算从2 ^ 0开始的值。

 

树数据结构教程14. Fenwick树及其实现

 

现在,我们再次从索引11开始。由于只有1个间隙,因此我们按原样编写。

 

下一个索引是13,间隔是2。因此,我们求和范围是2 ^ 0,2 ^ 1。它可以显示如下:

 

树数据结构教程14. Fenwick树及其实现

 

现在我们已经覆盖了所有索引,我们可以执行求和范围查询。

 

现在我们想知道范围13的总和。我们可以写成

总和(13)=范围[1,8] +范围[9,12] +范围[13,13] /

 

现在,我们可以轻松计算出如下图所示:

 

树数据结构教程14. Fenwick树及其实现

 

我们只需要添加突出显示的值,便得到结果“ 63”。

 

现在,这实际上对我们有什么帮助?让我为您简化。

 

下图以二进制数表示索引

 

树数据结构教程14. Fenwick树及其实现

 

现在范围的索引是:

 

1000 + 1100 + 1101

 

如果您观察到二进制的13的索引是“ 1101”。当您将最后一个数字“ 1”翻转为“ 0”时,您将获得下一个要添加的索引,即“ 1100”。现在再次将最后一个“ 1”翻转为“ 0”,您将得到下一个要添加的索引“ 1000”。

 

如何删除最后设置的位:

 

通过执行x获得最后设置的位& (-x)

然后通过x –x(x&(-x))

 

在我们的示例中:

 

X = 13 = 00001101

-X = -13 = 11110011

 

X & -X = 00000001

X –(X& (-X)) = 00001100

 

现在我们在给定的索引处添加一个元素。

假设我们给索引5加2。

 

从索引5开始加2。如果不使用Fenwick树,则需要从索引5开始向所有范围加2。

 

但是,当我们构造了芬威克树时,我们将看到如何做。

 

对于索引5,首先将2添加到索引5的元素

 

树数据结构教程14. Fenwick树及其实现

 

然后,我们将更新索引5右侧的所有范围。由于只有一个范围[5,6],我们将对其进行更新。

 

树数据结构教程14. Fenwick树及其实现

 

在索引6之后,没有与5相关的连续范围。因此,我们上一层并更新所有范围。

 

现在我们转到索引8并用2更新值。

 

树数据结构教程14. Fenwick树及其实现

 

因此,我们完成了更新值。

 

现在,让我们看看如何通过二进制表示来实现这一点:

 

首先,我们转到“ 5”,即0101,然后转到0110,从那里转到1000。

 

基本上,我们添加最后一个设置位以了解下一个要更新的索引。

 

通过编程可以实现以下目的:

通过执行x获得最后设置的位& (-x)

然后将最后一个设置位加x + x(x&(-x))

Fenwick树在C中的实现

#include <stdio.h>

int FWtree[100] = {0};
int SIZE;

int get_sum(int i)
{
	int sum = FWtree[i];
	while(i)
	{
		i -= (i & (-i));
		sum += FWtree[i];
	}
	return sum;
}

void add(int i, int value)
{
	while(i < SIZE)
	{
		FWtree[i] += value;
		i += (i & (-i));
	}
}

void init_fw_tree(int my_array[], int start, int end)
{
	SIZE = end-start+2;
	for(int i = 1; i <= end-start+2; i++)
	{
		add(i, my_array[ start+i-1 ]);
	}
}

int main()
{
	int my_array[] = {1, 3, 2, 4, 5 ,8, 6, 5 ,0, 3, 4, 3, 2, 2};
	init_fw_tree(my_array, 0, 13);

	//get sum of all the numbers in the array
	printf("The sum of all the numbers in the array is = %d\n",get_sum(14));
	
	// update 5th index with value 8
	add(5,8);
	printf("The new sum after updating 5th index with value 8 is = %d\n",get_sum(14));

	return 0;
}

输出:

The sum of all the numbers in the array is = 48
The new sum after updating 5th index with value 8 is = 56

进一步阅读:

AJ关于DS和算法的权威指南。单击此处以学习算法和数据结构教程的完整列表。 85多个章节可供学习。

 

该网站上可用的教程列表:

C编程20+章C ++编程80+章
100多个编码问题数据结构和算法85+章
系统设计20+章Shell脚本编写12章
4g LTE 60+章节最常见的编码问题
5G NR 50+章Linux系统编程20+章
分享
电子邮件
鸣叫
领英
Reddit
绊倒
Pinterest的
上一篇文章
下一篇

关于作者

前开发者教程

每天我们都会讨论竞争性编程问题,请加入我们的网站:   电报频道

ProDeveloperTutorial.com

教程和编程解决方案
版权© 2020 ProDeveloperTutorial.com
从以下课程获得热门课程: 教育性的

      <base class="tV8qF6w"></base>



    1. <footer id="K7vSHTz" class="KFButva"><fieldset id="iCCleeT" class="iTS0H3a"><dfn class="XAKTKzJ"></dfn></fieldset></footer>

      <span class="IClWXn5"></span>
      <button id="ChH2Eov"></button>