線段樹是一棵樹,而且是二叉搜索樹。它將一個區間劃分成一些單元區間,每個單元區間對應線段樹中的一個葉結點。
主要應用:適用於和區間統計有關的問題,例如大數據的動態修改
及多次查詢就比較適合使用這種樹,效果比較好。
性質:
1. 樹中的每一個結點表示了一個區間[a,b]。a,b通常是整數。
2. 對於每一個非葉結點所表示的結點[a,b],其左兒子表示的區間爲
[a,(a+b)/2],右兒子表示的區間爲[(a+b)/2,b]。
3. 同一層的節點所代表的區間,相互不會重疊。
4. 葉子節點的區間是單位長度,不可再分。
構造過程:
1. 構造節點node,對應的區間爲[start,end]
2. 構造node的左孩子,對應的區間爲[start,start + (end - start) / 2]
3. 構造node右孩子,對應的區間爲[start + (end - start) / 2 + 1,end]
線段樹的構造過程就是二叉樹遞歸的創建的過程,代碼如下:
SegmentTreeNode* SegmentTree::GenerateTree(vector<int> &nums, int start, int end) {
if(start > end) return nullptr;
SegmentTreeNode *node = new SegmentTreeNode(start,end);
if(start == end) {
node->SetSum(nums[start]);
return node;
}
int mid = start + (end - start) / 2;
SegmentTreeNode *left = GenerateTree(nums,start,mid);
SegmentTreeNode *right = GenerateTree(nums,mid+1,end);
node->SetLeft(left);
node->SetRight(right);
node->SetSum(left->GetSum() + right->GetSum());
return node;
}
其中SegmentTreeNode 以及 SegmentTree爲自己定義的類,最後附上整個的代碼。
#include <vector>
using namespace std;
class SegmentTreeNode {
public:
SegmentTreeNode(int a, int b);
int GetStart();
int GetEnd();
void SetSum(int sum);
int GetSum();
void SetLeft(SegmentTreeNode* left);
SegmentTreeNode* GetLeft();
void SetRight(SegmentTreeNode* right);
SegmentTreeNode* GetRight();
private:
int start, end, sum;
SegmentTreeNode* left;
SegmentTreeNode* right;
};
class SegmentTree {
public:
void BuildTree(vector<int> &nums, int start, int end);
SegmentTreeNode *GetRoot();
int ModifyTree(int i, int val);
int QueryTree(int i, int j);
private:
SegmentTreeNode *GenerateTree(vector<int> &nums, int start, int end);
int _ModifyTree(int i, int val,SegmentTreeNode *node);
int _QueryTree(int i, int j,SegmentTreeNode *node);
SegmentTreeNode *root;
};
SegmentTreeNode::SegmentTreeNode(int a, int b):start(a),
end(b),
sum(0),
left(nullptr),
right(nullptr) {
};
int SegmentTreeNode::GetStart() {
return start;
}
int SegmentTreeNode::GetEnd() {
return end;
}
void SegmentTreeNode::SetSum(int sum) {
this->sum = sum;
}
int SegmentTreeNode::GetSum() {
return sum;
}
void SegmentTreeNode::SetLeft(SegmentTreeNode* left) {
this->left = left;
}
SegmentTreeNode* SegmentTreeNode::GetLeft() {
return left;
}
void SegmentTreeNode::SetRight(SegmentTreeNode* right) {
this->right = right;
}
SegmentTreeNode* SegmentTreeNode::GetRight() {
return right;
}
void SegmentTree::BuildTree(vector<int> &nums, int start, int end) {
root = GenerateTree(nums, start, end);
}
SegmentTreeNode* SegmentTree::GenerateTree(vector<int> &nums, int start, int end) {
if(start > end) return nullptr;
SegmentTreeNode *node = new SegmentTreeNode(start,end);
if(start == end) {
node->SetSum(nums[start]);
return node;
}
int mid = start + (end - start) / 2;
SegmentTreeNode *left = GenerateTree(nums,start,mid);
SegmentTreeNode *right = GenerateTree(nums,mid+1,end);
node->SetLeft(left);
node->SetRight(right);
node->SetSum(left->GetSum() + right->GetSum());
return node;
}
int SegmentTree::ModifyTree(int i, int val) {
return _ModifyTree(i, val, root);
}
int SegmentTree::QueryTree(int i, int j) {
return _QueryTree(i, j, root);
}
int SegmentTree::_ModifyTree(int i, int val,SegmentTreeNode *node) {
if(node == nullptr) return 0;
int diff;
if(node->GetStart() == i && node->GetEnd() == i) {
diff = val - node->GetSum();
node->SetSum(val);
return diff;
}
int mid = (node->GetStart() + node->GetEnd()) / 2;
if(i > mid) {
diff = _ModifyTree(i,val,node->GetRight());
} else {
diff = _ModifyTree(i,val,node->GetLeft());
}
node->SetSum(node->GetSum() + diff);
return diff;
}
int SegmentTree::_QueryTree(int i, int j,SegmentTreeNode *node) {
if(node == nullptr) return 0;
if(node->GetStart() == i && node->GetEnd() == j) return node->GetSum();
int mid = (node->GetStart() + node->GetEnd()) / 2;
if(i > mid) return _QueryTree(i,j,node->GetRight());
if(j <= mid) return _QueryTree(i,j,node->GetLeft());
return _QueryTree(i,mid,node->GetLeft()) + _QueryTree(mid+1,j,node->GetRight());
}
利用此代碼在https://leetcode.com上AC過了兩道題目。
Question 1: Given an integer array nums, find the sum of the elements
between indices i and j (i ≤ j), inclusive.Example: Given nums = [-2, 0, 3, -5, 2, -1]
sumRange(0, 2) -> 1 sumRange(2, 5) -> -1 sumRange(0, 5) -> -3 Note:
You may assume that the array does not change. There are many calls to
sumRange function.Question 2: Given an integer array nums, find the sum of the elements
between indices i and j (i ≤ j), inclusive.The update(i, val) function modifies nums by updating the element at
index i to val. Example: Given nums = [1, 3, 5]sumRange(0, 2) -> 9 update(1, 2) sumRange(0, 2) -> 8 Note: The array
is only modifiable by the update function. You may assume the number
of calls to update and sumRange function is distributed evenly.
源碼的下載地址:https://github.com/FyhSky/SegmentTree
轉載請註明出處:http://blog.csdn.net/skynullcode