Algorithm 用于反转log(n)中的子阵列的数据结构
构建具有以下功能的数据结构:Algorithm 用于反转log(n)中的子阵列的数据结构,algorithm,data-structures,binary-tree,binary-search-tree,Algorithm,Data Structures,Binary Tree,Binary Search Tree,构建具有以下功能的数据结构: set(arr,n)-使用长度为n的数组arr初始化结构。时间O(n) fetch(i)-fetcharr[i]。时间O(log(n)) invert(k,j)-(当0以下是我们如何设计这种数据结构的方法。 事实上,使用平衡二叉搜索树是一个好主意 首先,让我们成对存储数组元素(索引,值)。 自然地,元素是按索引排序的,因此树的顺序遍历将按其原始顺序生成数组 现在,如果我们保持一个平衡的二叉搜索树,并将子树的大小存储在每个节点中,我们就可以在O(logn)中执行fet
set(arr,n)
-使用长度为n
的数组arr
初始化结构。时间O(n)
fetch(i)
-fetcharr[i]
。时间O(log(n))
invert(k,j)
-(当0以下是我们如何设计这种数据结构的方法。
事实上,使用平衡二叉搜索树是一个好主意
首先,让我们成对存储数组元素(索引,值)
。
自然地,元素是按索引排序的,因此树的顺序遍历将按其原始顺序生成数组
现在,如果我们保持一个平衡的二叉搜索树,并将子树的大小存储在每个节点中,我们就可以在O(logn)
中执行fetch
接下来,让我们假设我们存储索引。
相反,我们仍然像对待(索引,值)
对那样排列元素,但只存储值。
索引
现在隐式存储,可以按如下方式计算。
从根节点开始,向下到目标节点。
每当我们移动到左子树时,索引
不会改变。
移动到右子树时,将左子树的大小加上一(当前顶点的大小)添加到索引中
此时我们得到的是一个存储在平衡二叉搜索树中的定长数组。它需要O(logn)
来访问(读或写)任何元素,而不是普通定长数组的O(1)
,因此现在是时候从所有麻烦中获得一些好处了
下一步是设计一种方法,在O(logn)
中,根据左侧部分所需的大小,将数组拆分为左侧部分和右侧部分,并通过串联合并两个数组。
这一步引入了对我们选择的平衡二叉搜索树的依赖性。
是显而易见的候选者,因为它构建在拆分和合并原语之上,所以这种改进是免费的。
也许在O(logn)
中拆分a或a也是可能的(尽管我承认我自己并没有试图弄清楚细节)
目前,该结构已经比数组更强大:它允许在O(logn)
中拆分和串联“数组”,尽管元素访问速度也和O(logn)
一样慢。
请注意,如果此时仍显式存储索引
,这将是不可能的,因为索引将在拆分或合并操作的右侧部分断开
最后,是时候引入反转操作了。
让我们在每个节点中存储一个标志,以指示是否必须反转该节点的整个子树。
此标志将延迟传播:无论何时访问节点,在执行任何操作之前,请检查标志是否为true
。
如果是这种情况,请交换左右子树,在两个子树的根节点中切换(true-false
)标志,并将当前节点中的标志设置为false
现在,当我们要反转子阵列时:
- 通过两次拆分操作将阵列拆分为三部分(子阵列之前、子阵列本身以及子阵列之后)
- 切换(
true-false
)中间(子阵列)部分根中的标志
- 然后通过两个合并操作将三个部分按原始顺序合并