线段树也是一种二叉树,只不过它的节点用来表示一个区间,其特征是将当前区间二分后分别作为左右孩子节点
的区间,如下图(来自百度图片)所示:
线段树在处理区间覆盖问题时,比较有用处,它支持的基本操作如下:
1) 给定区间[i, j],创建一个线段树;【时间复杂度为O(j – i)】
2) 将某个区间[i,j]插入到线段树中; 【时间复杂度为O(log(j-i))】
3) 从线段树中删除某个区间[i,j]。【时间复杂度为O(log(j-i)】
下面是使用C语言实现的一个线段树(VC++编译器编译运行):
/*
* Author:puresky
* Date: 2008/12/22
* Version: 线段树1.0,
* Refer to:数据结构教程(V2)
*/
#include <stdio.h>
#include <stdlib.h>
typedef struct ltree_node
{
int i, j; //表示区间[i, j]
int cover; //表示区间被覆盖的次数
struct ltree_node *left, *right; //左右儿子节点
} LTree;
//创建线段树
LTree* ltree_create(int i, int j)
{
if(i > j) return (NULL);
LTree* pNode = NULL;
pNode = (LTree*)malloc(sizeof(LTree));
pNode->i = i;
pNode->j = j;
pNode->cover = 0;
if(j - i > 1)
{
int mid = i + (j - i) / 2;
pNode->left = ltree_create(i, mid);
pNode->right = ltree_create(mid, j);
}
else
{
pNode->left = pNode->right = NULL;
}
return pNode;
}
//插入一个区间
void ltree_insert(LTree* ltree, int i, int j)
{
if(i > j) return;
if(i <= ltree->i && ltree->j <= j)
{
ltree->cover++;
}
else
{
int mid = ltree->i + (ltree->j - ltree->i) / 2;
if(j <= mid)
{
ltree_insert(ltree->left, i, j);
}
else if(mid <= i)
{
ltree_insert(ltree->right, i, j);
}
else
{
ltree_insert(ltree->left, i, mid);
ltree_insert(ltree->right, mid, j);
}
}
}
//删除一个区间,注意只能删除已经插入的区间
void ltree_delete(LTree* ltree, int i, int j)
{
if(i > j) return;
if(i <= ltree->i && ltree->j <= j)
ltree->cover--;
else
{
int mid = ltree->i + (ltree->j - ltree->i) / 2;
if(j <= mid)
{
ltree_delete(ltree->left, i, j);
}
else if(i >= mid)
{
ltree_delete(ltree->right, i, j);
}
else
{
ltree_delete(ltree->left, i, mid);
ltree_delete(ltree->right, mid, j);
}
}
}
//输出线段树
void ltree_print(LTree* ltree, int depth)
{
if(ltree)
{
int i;
for(i = 0; i < depth; ++i) printf(" ");
printf("[%d,%d]:%d\n", ltree->i, ltree->j, ltree->cover);
ltree_print(ltree->left, depth + 1);
ltree_print(ltree->right, depth + 1);
}
}
//释放线段树内存
void ltree_destroy(LTree* ltree)
{
if(ltree)
{
LTree* pNode = ltree;
ltree_destroy(ltree->left);
ltree_destroy(ltree->right);
//free(pNode);
}
}
int main(int argc, char** argv)
{
//测试线段树
LTree* root = ltree_create(1, 10);
ltree_print(root, 0);
ltree_insert(root, 3, 6);
ltree_print(root, 0);
ltree_insert(root, 7, 9);
ltree_print(root, 0);
ltree_delete(root, 3, 5);
ltree_print(root, 0);
ltree_destroy(root);
system("pause");
return 0;
}