線段樹-Segment tree

O(logn)的查找數組區間和以及修改數組中的值

涉及到的知識點

  • 遞歸
  • 徹底二叉樹

其中涉及到的操做

  • build_tree()把一個數字構建成一個樹
  • query_tree()返回L,R一個區間的和
  • update_tree()更改數組中的下標爲idx值爲val

SegmentTree


完整代碼

#include<stdio.h>
#define MAX_LEN 100000
void build_tree(int arr[], int tree[], int node, int start, int end) {
	if (start == end) { //遞歸出口
		tree[node] = arr[start];
		return;
	}

	int mid = (start + end) / 2;// 區間分界線
	int left_node = 2 * node + 1;//左孩子
	int right_node = 2 * node + 2;

	build_tree(arr, tree, left_node, start, mid); //[start, mid]的區間
	build_tree(arr, tree, right_node, mid + 1, end);// [mid + 1, end]的區間
	tree[node] = tree[left_node] + tree[right_node]; // 樹的結點爲左右子結點的和

}

void update_tree(int arr[], int tree[], int node, int start, int end, int idx, int val) {

	if (start == end) { // 遞歸出口
		arr[idx] = val; // 修改數組的值
		tree[node] = val;// 更改樹的結點值
		return;
	}

	int mid = (start + end) / 2;
	int left_node = 2 * node + 1;
	int right_node = 2 * node + 2;

	if (start <= idx && idx <= mid) { //在左子區間
		update_tree(arr, tree, left_node, start, mid, idx, val);
	}
	else  { // 在右子區間
		update_tree(arr, tree, right_node, mid + 1, end, idx, val);
	}

	tree[node] = tree[left_node] + tree[right_node];

}

int query_tree(int arr[], int tree[], int node, int start, int end,int L, int R) {

	if (R < start || L > end) { //不知足區間要求 返回0
		return 0;
	}
	else if (start == end) { //到了葉子結點返回

		return tree[node];
	}
	else if (R >= end && L <= start) { //結點在LR範圍以內
		return tree[node];
	}

	int mid = (start + end) / 2;
	int left_node = node * 2 + 1;
	int right_node = node * 2 + 2;
	int sum_left = query_tree(arr, tree, left_node, start, mid, L, R);
	int sum_right = query_tree(arr, tree, right_node, mid + 1, end, L, R);

	return sum_left + sum_right;
}

int main() {
	int arr[] { 1, 3, 5, 7, 9 ,11};
	int size = 6;
	int tree[MAX_LEN] = { 0 };
	build_tree(arr, tree, 0, 0, size - 1);
	
	update_tree(arr, tree, 0, 0, size - 1, 4, 6);

	int s = query_tree(arr, tree, 0, 0, size - 1, 2, 5);
	printf("%d\n", s);
	return 0;
}
相關文章
相關標籤/搜索