Handwriting first field a first mirror segment tree

Quiet night most suitable brush algorithm the subject. Brush with the brush found a fun segment tree data structure is called, is said to be a frequent visitor to the algorithm contest Oh, so he wrote a simple play.

principle

For tree line comrades venue, inside a principle and diagram: Baidu Encyclopedia, segment tree

Needs and pain points

I use it primarily to quickly find and digital, and digital and find within range again after modify array elements within a certain range of the array. One can imagine, I have two requirements: sum modification.

Under normal circumstances, because we do not want to sort the array, then we can be modified with the complexity of O (1), and to achieve the summation with O (n) complexity of traversing range. However, when we need to frequently operate summation, beautiful to look at O ​​(n) becomes a mosquito blood on the wall, no longer had red roses, so that we can optimize it.

I chose the tree line, typical of space for time. I realized with an array of binary tree line, with four times the extra space. Fengyun binary tree leaf node is the various elements of the original array, non-leaf node is stored in a certain range and has been gradually merged into the root zone, the root node is precisely what the original array elements from start to finish and maximum range, specific can look at the code, the code personally feel more intuitive than the text ha ha. Such a process would sum operation becomes O (logN), and the corresponding modification operations also increased to O (logN), two pairs of the number of levels and often is always better than a linear one constant, is not it?

Talk is cheap. Show me the code.

The first is to build tree line, and then understand the principles as a binary tree as the recursion engage in direct Jiuhaola:

type segmentTree struct {
	data []int //原始数组
	tree []int //线段树数组
}

//初始化线段树,至于为什么需要4倍空间,只要咱们理解了二叉树就一目了然了,线段树每个节点存储的就是某一段的区间和
func NewSegmentTree(num []int) *segmentTree {
	countNum := len(num)
	data := make([]int, countNum)
	for k, v := range num {
		data[k] = v
	}
	tree := make([]int, 4*countNum)
	if countNum > 0 {
		var buildTree func(int, int, int)
		buildTree = func(index, left, right int) {
			if left == right {
				tree[index] = num[left]
				return
			}
			leftChild := leftChild(index)
			rightChild := rightChild(index)
			mid := left + ((right - left) >> 1)
			buildTree(leftChild, left, mid)
			buildTree(rightChild, mid+1, right)
			tree[index] = tree[leftChild] + tree[rightChild]
		}
		buildTree(0, 0, countNum-1)
	}
	return &segmentTree{data, tree}
}
复制代码

Then is the summation operations, we put each section and saved separately Well, essentially it becomes a node on the binary tree looking for constant, so of course is O (logN) of:

//求和操作,只需要通过递归来找到最近的区间和就好
func (st *segmentTree) SumRange(start, end int) int {
	var sum func(int, int, int, int, int) int
	sum = func(index, left, right, start, end int) int {
		if left == start && right == end {
			return st.tree[index]
		}
		leftChild := leftChild(index)
		rightChild := rightChild(index)
		mid := left + ((right - left) >> 1)
		if start >= mid+1 {
			return sum(rightChild, mid+1, right, start, end)
		} else if end <= mid {
			return sum(leftChild, left, mid, start, end)
		}
		return sum(leftChild, left, mid, start, mid) + sum(rightChild, mid+1, right, mid+1, end)
	}
	return sum(0, 0, len(st.data)-1, start, end)
}
复制代码

Modify the operation, a good memory as bad written with a pen drawing on it:

//修改操作,递归找到叶子节点改掉索引对应的值,然后回溯的过程改掉包含索引的所有区间的和
func (st *segmentTree) Update(i int, value int) {
	countNum := len(st.data)
	if i >= len(st.data) {
		return
	}
	st.data[i] = value
	var up func(int, int, int)
	up = func(index, left, right int) {
		if left == right {
			st.tree[index] = value
			return
		}
		leftChild := leftChild(index)
		rightChild := rightChild(index)
		mid := left + ((right - left) >> 1)
		if i >= mid+1 {
			up(rightChild, mid+1, right)
		} else if i <= mid {
			up(leftChild, left, mid)
		}
		st.tree[index] = st.tree[leftChild] + st.tree[rightChild]
	}
	up(0, 0, countNum-1)
}

func leftChild(i int) int {
	return (i << 1) + 1
}
func rightChild(i int) int {
	return (i << 1) + 2
}
复制代码

Novice code optimization is always a great space, passing through the gentlemen to let me know, oh.

Of course, this is just a simple tree line, can only solve my little demand. There are more programs, such as a linked list to build the tree will certainly be more flexible, and the segment tree is not only used to sum can achieve more operation window for more fun can be lazy update, not every change anxious to re-build the whole tree can come little by little, so that more optimized performance. If you are interested in tree line, then go to find information O ~ ( ¯)¯ ) O

Algorithm dreamer , come play with me algorithm, play music and talk about literature, our ideas together!

Reproduced in: https: //juejin.im/post/5d0b0cd3e51d4510a73280cb

Guess you like

Origin blog.csdn.net/weixin_34004576/article/details/93180844