线段树是一种平衡二叉搜索树(完全二叉树),它将一个线段区间划分成一些单元区间。对于线段树中的每一个非叶子节点[a,b],他的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b],最后的叶子节点数目为N,与数组下标对应。线段树的一般包括建立、查询、插入、更新等操作,建立规模为N的时间复杂度是O(NlogN),其他操作时间复杂度为O(logN)。
平衡二叉搜索树(完全二叉树)是指除了最后一层,其他层都是满的二叉树。
线段树最大的价值是平衡,因为线段树是平衡二叉树。很多题目可以通过平衡二叉树达到完美的时间复杂度。
#include <vector>
//线段树的构造
void build_segment_tree(std::vector<int>& nums, std::vector<int>& value, int pos, int left, int right)
{
if (left==right)
{
value[pos] = nums[left];
return;
}
int mid = (left + right) / 2;
build_segment_tree(nums, value, 2 * pos + 1, left, mid);
build_segment_tree(nums, value, 2 * pos + 2, mid+1, right);
value[pos] = value[2 * pos + 1] + value[2 * pos + 2];
}
//线段树的遍历
void print_segment_tree(std::vector<int>& value, int pos, int left, int right, int layer)
{
for (int i = 0; i < layer; i++)
{
printf("---");
}
printf("[%d %d] [%d]: %d\n", left, right, pos, value[pos]);
if (left==right)
{
return;
}
int mid = (left + right) / 2;
print_segment_tree(value, 2 * pos + 1, left, mid, layer + 1);
print_segment_tree(value, 2 * pos + 2, mid + 1, right, layer + 1);
}
//线段树的求和
int sum_range_segment_tree(std::vector<int>& value, int pos, int left, int right, int qleft, int qright)
{
if (qleft>right||qright<left)
{
return 0;
}
if (qleft<=left&&qright>=right)
{
return value[pos];
}
int mid = (left + right) / 2;
return sum_range_segment_tree(value, 2 * pos + 1, left, mid, qleft, qright) + sum_range_segment_tree(value, 2 * pos + 2, mid + 1, right, qleft, qright);
}
//线段树的更新
void update_segment_tree(std::vector<int>& value, int pos, int left, int right, int index, int new_value)
{
if (left==right&&left==index)
{
value[pos] = new_value;
return;
}
int mid = (left + right) / 2;
if (index<=mid)
{
update_segment_tree(value, 2*pos+1, left, mid, index, new_value);
}
else
{
update_segment_tree(value, 2 * pos + 2, mid+1, right, index, new_value);
}
value[pos] = value[2 * pos + 1] + value[2 * pos + 2];
}
int main()
{
std::vector<int> nums;
for (int i = 0; i < 6; i++)
{
nums.push_back(i);
}
std::vector<int> value;
for (int i = 0; i < 24; i++)
{
value.push_back(0);
}
build_segment_tree(nums, value, 0, 0, nums.size() - 1);
printf("segment tree:\n");
print_segment_tree(value, 0,0,nums.size()-1,0);
int sum_range = sum_range_segment_tree(value, 0, 0, nums.size() - 1, 2, 4);
printf("sum_range [2,5]=%d\n", sum_range);
update_segment_tree(value, 0, 0, nums.size() - 1, 2, 10);
printf("segment_tree:\n");
print_segment_tree(value,0,0,nums.size()-1,0);
return 0;
}
运行结果为:
segment tree:
[0 5] [0]: 15
---[0 2] [1]: 3
------[0 1] [3]: 1
---------[0 0] [7]: 0
---------[1 1] [8]: 1
------[2 2] [4]: 2
---[3 5] [2]: 12
------[3 4] [5]: 7
---------[3 3] [11]: 3
---------[4 4] [12]: 4
------[5 5] [6]: 5
sum_range [2,5]=9
segment_tree:
[0 5] [0]: 23
---[0 2] [1]: 11
------[0 1] [3]: 1
---------[0 0] [7]: 0
---------[1 1] [8]: 1
------[2 2] [4]: 10
---[3 5] [2]: 12
------[3 4] [5]: 7
---------[3 3] [11]: 3
---------[4 4] [12]: 4
------[5 5] [6]: 5