Implementation:Segment Tree 线段树
早就听人提起过线段树,今天有题搞不出来,讨论上说要用一下线段树,看了下,本质上是空间划分索引,只不过是一维上面的,如果在二维则是四叉树,三维则是八叉树,如果可以动态调整那么跟R-Tree就很相似了,他们都可以对范围查询做出响应。参照书上写了一个,虽然不多,但是渣渣也写的很是费力
#include <iostream> #include <cstdlib> #include <vector> using namespace std; class SegmentTree { private: int *mem; int capacity; int storage_size; private: void init_level_update() { int k = capacity - 1; while (--k >= 0) { int L = (k<<1) + 1; int R = L + 1; mem[k]= min(mem[L], mem[R]); } } int query(int a, int b, int idx, int L, int R) { if (b <= L || a >= R) return INT_MAX; if (a <= L && R <= b) return mem[idx]; int ml = query(a, b, (idx<<1) + 1, L, (L+R)/2); int mr = query(a, b, (idx<<1) + 2, (L+R)/2, R); return min(ml, mr); } void init_mem(int _capacity) { if (_capacity <= 0) { capacity = 0; return; } int n = 1; while (n < _capacity) n<<=1; capacity = n; storage_size = capacity * 2 - 1; mem = new int[storage_size]; int k = 0; while (k < storage_size) mem[k++] = INT_MAX; } public: SegmentTree(int _capacity) { init_mem(_capacity); } SegmentTree(vector<int>::iterator begin, vector<int>::iterator end) { capacity = end - begin; init_mem(capacity); int k = capacity - 1; vector<int>::iterator iter = begin; while (iter != end) mem[k++] = *iter++; init_level_update(); } ~SegmentTree() { delete[] mem; } // update value in original data index void update(int idx, int val) { if (idx >= capacity || idx < 0) return; int k = idx + capacity - 1; // internal storage index mem[k] = val; while (k > 0) { k = (k - 1) >> 1; int L = (k << 1) + 1; int R = L + 1; mem[k] = min (mem[L], mem[R]); } } // retrive the min value in index range [a, b) int query(int a, int b) { return query(a, b, 0, 0, capacity); } void print_mem(const char* msg) { cout<<msg<<endl; for (int i=0; i<(capacity*2-1); i++) { cout<<mem[i]<<" "; } cout<<endl; } }; void test(const char* msg, SegmentTree& seg_tree, int* data, int size) { cout<<msg<<endl; for (int i=0; i<=size; i++) { for (int j=i+1; j<=size; j++) { int tmin = seg_tree.query(i, j); cout<<"min of ("<<i<<","<<j<<") = "<<tmin<<endl; int amin = INT_MAX; for (int k=i; k<j; k++) if (data[k] < amin) amin = data[k]; if (amin != tmin) cout<<"fail"<<endl; else cout<<"ok"<<endl; } } } int main() { int h[] = {6, 2, 5, 4, 5, 3, 6}; int size= sizeof(h) / sizeof(int); vector<int> hs(h, h + size); SegmentTree seg_tree(hs.begin(), hs.end()); test("Test construction with data :", seg_tree, h, size); SegmentTree init_empty_tree(size); for (int i=0; i<size; i++) init_empty_tree.update(i, h[i]); test("Test construction without data", init_empty_tree, h, size); system("pause"); return 0; }
下面是一个带有返回最小值索引值的改进版本
class SegmentTree { private: int *mem; int *idx; int capacity; int storage_size; private: void init_level_update() { int k = capacity - 1; while (--k >= 0) { int L = (k<<1) + 1; int R = L + 1; if (mem[L] < mem[R]) { mem[k] = mem[L]; idx[k] = idx[L]; } else { mem[k] = mem[R]; idx[k] = idx[R]; } } } pair<int, int> query(int a, int b, int idx, int L, int R) { if (b <= L || a >= R) return make_pair(INT_MAX, -1); if (a <= L && R <= b) return make_pair(mem[idx], this->idx[idx]); pair<int, int> ml = query(a, b, (idx<<1) + 1, L, (L+R)/2); pair<int, int> mr = query(a, b, (idx<<1) + 2, (L+R)/2, R); return ml.first < mr.first ? ml : mr; } void init_mem(int _capacity) { if (_capacity <= 0) { capacity = 0; return; } int n = 1; while (n < _capacity) n<<=1; capacity = n; storage_size = capacity * 2 - 1; mem = new int[storage_size]; idx = new int[storage_size]; int k = 0; while (k < storage_size) mem[k++] = INT_MAX; k = capacity - 1; int i = 0; while (k < storage_size) idx[k++] = i++; } public: SegmentTree(int _capacity) { init_mem(_capacity); } SegmentTree(vector<int>::iterator begin, vector<int>::iterator end) { capacity = end - begin; init_mem(capacity); int k = capacity - 1; vector<int>::iterator iter = begin; while (iter != end) mem[k++] = *iter++; init_level_update(); } ~SegmentTree() { delete[] mem; delete[] idx; } // update value in original data index void update(int index, int val) { if (index >= capacity || idx < 0) return; int k = index + capacity - 1; // internal storage index mem[k] = val; while (k > 0) { k = (k - 1) >> 1; int L = (k << 1) + 1; int R = L + 1; if (mem[L] < mem[R]) { mem[k] = mem[L]; idx[k] = idx[L]; } else { mem[k] = mem[R]; idx[k] = idx[R]; } } } // retrive the min value in index range [a, b) pair<int, int> query(int a, int b) { return query(a, b, 0, 0, capacity); } void print_mem(const char* msg) { cout<<msg<<endl; for (int i=0; i<(capacity*2-1); i++) { cout<<mem[i]<<" "; } for (int i=0; i<capacity * 2 - 1; i++) { cout<<idx[i]<<","; } cout<<endl; } };
参考:
挑战程序设计竞赛第二版