🏆 作者简介,愚公搬代码 🏆《头衔》:华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,阿里云专家博主,腾讯云优秀博主,掘金优秀博主,51CTO博客专家等。 🏆《近期荣誉》:2022年CSDN博客之星TOP2,2022年华为云十佳博主等。
🏆《博客内容》:.NET、Java、Python、Go、Node、前端、IOS、Android、鸿蒙、Linux、物联网、网络安全、大数据、人工智能、U3D游戏、小程序等相关领域知识。
🏆🎉欢迎 👍点赞✍评论⭐收藏
数据结构是计算机科学中的一个重要概念,它描述了数据之间的组织方式和关系,以及对这些数据的访问和操作。常见的数据结构有:数组、链表、栈、队列、哈希表、树、堆和图。
线段树的基本思想是将区间划分为若干个较小的区间,然后将这些小区间存储在树状结构中。通过使用线段树,我们可以有效地回答各种与区间有关的问题,例如区间最大值、区间求和等。
线段树的构建过程通常采用递归的方法。首先,将整个区间划分成两个子区间,然后递归对子区间继续进行划分,直到划分到单个元素为止。每个小区间的信息存储在一个对应的节点中,而这些节点通过父子关系组成了一棵树状结构,即线段树。
线段树的常见操作包括:查询区间信息、区间修改和单点修改。查询区间信息通常采用递归的方式,将区间不断划分为子区间,直到划分到与查询区间完全重叠或包含的小区间为止。对于修改操作,我们需要递归地修改涉及到的所有小区间,并更新父节点的信息。单点修改和区间修改的思想较为类似,都需要将修改操作递归地推至对应的叶节点,然后逐层向上传递修改后的信息。
线段树的时间复杂度通常为 O(logn),其中 n 是区间长度。因此,线段树通常用于需要高效处理区间信息的问题。
以下是C#实现线段树的常用操作:
/// <summary>
/// 线段树:线段树是二叉树的一种,常常被用于求区间和与区间最大值等操作
/// </summary>
public class SegmentTree
{
List<int> _orignalData = new List<int>();
List<int?> _tree = new List<int?>();
public SegmentTree()
{
for (int i = 0; i < 1000; i++)
{
_tree.Add(null);
}
}
public void Print()
{
for (int i = 0; i < _tree.Count; i++)
{
if (_tree[i] == null)
{
continue;
}
Console.WriteLine($"第{i}:{_tree[i]}");
}
}
public void Fill(List<int> data)
{
_orignalData = data;
Fill(0, 0, _orignalData.Count - 1);
}
private void Fill(int node, int start, int end)
{
if (start == end)
{
_tree[node] = _orignalData[start];
}
else
{
int mid = (start + end) / 2;
int leftNode = 2 * node + 1;
int rightNode = 2 * node + 2;
Fill(leftNode, start, mid);
Fill(rightNode, mid + 1, end);
_tree[node] = _tree[leftNode] + _tree[rightNode];
}
}
public void Set(int index, int val)
{
SetValue(0, 0, _orignalData.Count - 1, index, val);
}
private void SetValue(int node, int start, int end, int index, int val)
{
if (start == end)
{
_orignalData[index] = val;
_tree[node] = val;
}
else
{
int mid = (start + end) / 2;
int leftNode = 2 * node + 1;
int rightNode = 2 * node + 2;
if (index >= start && index <= mid)
{
SetValue(leftNode, start, mid, index, val);
}
else
{
SetValue(rightNode, mid + 1, end, index, val);
}
_tree[node] = _tree[leftNode] + _tree[rightNode];
}
}
public int? GetSum(int left, int right)
{
return Query(0, 0, _orignalData.Count - 1, left, right);
}
private int? Query(int node, int start, int end, int left, int right)
{
if (right < start || left > end)
{
return 0;
}
else if (left <= start && end <= right)
{
return _tree[node];
}
else if (start == end)
{
return _tree[node];
}
else
{
int mid = (start + end) / 2;
int leftNode = 2 * node + 1;
int rightNode = 2 * node + 2;
int? sumLeft = Query(leftNode, start, mid, left, right);
int? sumRight = Query(rightNode, mid + 1, end, left, right);
return sumLeft + sumRight;
}
}
}这里实现了线段树的构建、区间查询和区间修改操作。其中,构建操作通过递归实现,区间查询和区间修改采用类似的递归思想。可以通过传入数组 nums 构建线段树,并使用 Query 方法查询区间信息,使用 Update 方法修改区间信息。
线段树是一种基于分治思想的数据结构,主要用于解决区间查询、区间修改等问题。它具有以下优点和缺点。
优点:
缺点:
线段树在解决区间查询、区间修改等问题时表现出色,但在一些特殊情况下可能并不是最优的选择。需要根据具体问题的特点选择合适的数据结构。
线段树(Segment Tree)是一种经典的数据结构,主要应用场景包括: