Ani*_*jee 5 .net c# stack-overflow recursion performance
这是情况,我正在开发一个二叉搜索树,并且在树的每个节点中,我打算存储它自己的高度,以便在avl树形成期间进一步平衡树.以前我有一个迭代方法来计算平衡树时节点的高度,如下所示.
(以下代码属于一个被称为AVLTree<T>子类的类BinarySearchTree<T>)
protected virtual int GetBalance(BinaryTreeNode<T> node)
{
if(node != null)
{
IEnumerable<BinaryTreeNode<T>> leftSubtree = null, righSubtree = null;
if (node.Left != null)
leftSubtree = node.Left.ToEnumerable(BinaryTreeTraversalType.InOrder);
if (node.Right != null)
righSubtree = node.Right.ToEnumerable(BinaryTreeTraversalType.InOrder);
var leftHeight = leftSubtree.IsNullOrEmpty() ? 0 : leftSubtree.Max(x => x.Depth) - node.Depth;
var righHeight = righSubtree.IsNullOrEmpty() ? 0 : righSubtree.Max(x => x.Depth) - node.Depth;
return righHeight - leftHeight;
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但它带来了很多性能开销.
所以我在插入时在每个节点中存储高度值BinarySearchTree<T>.现在在平衡期间,我能够避免这种迭代,并且我正在获得所需的性能AVLTree<T>.
但现在的问题是,如果我尝试按顺序插入大量数据说1-50000 BinarySearchTree<T>(不平衡它),我得到StackoverflowException.我正在提供导致它的代码.你能帮我找一个能避免这个例外的解决方案,也不会影响其子类的表现AVLTree<T>吗?
public class BinaryTreeNode<T>
{
private BinaryTreeNode<T> _left, _right;
private int _height;
public T Value {get; set; }
public BinaryTreeNode<T> Parent;
public int Depth {get; set; }
public BinaryTreeNode()
{}
public BinaryTreeNode(T data)
{
Value = data;
}
public BinaryTreeNode<T> Left
{
get { return _left; }
set
{
_left = value;
if (_left != null)
{
_left.Depth = Depth + 1;
_left.Parent = this;
}
UpdateHeight();
}
}
public BinaryTreeNode<T> Right
{
get { return _right; }
set
{
_right = value;
if (_right != null)
{
_right.Depth = Depth + 1;
_right.Parent = this;
}
UpdateHeight();
}
}
public int Height
{
get { return _height; }
protected internal set
{
_height = value;
if (Parent != null) {
Parent.UpdateHeight();
}
}
}
private void UpdateHeight()
{
if (Left == null && Right == null) {
return;
}
if(Left != null && Right != null)
{
if (Left.Height > Right.Height)
Height = Left.Height + 1;
else
Height = Right.Height + 1;
}
else if(Left == null)
Height = Right.Height + 1;
else
Height = Left.Height + 1;
}
}
Run Code Online (Sandbox Code Playgroud)
public class BinarySearchTree<T>
{
private readonly Comparer<T> _comparer = Comparer<T>.Default;
public BinarySearchTree()
{
}
public BinaryTreeNode<T> Root {get; set;}
public virtual void Add(T value)
{
var n = new BinaryTreeNode<T>(value);
int result;
BinaryTreeNode<T> current = Root, parent = null;
while (current != null)
{
result = _comparer.Compare(current.Value, value);
if (result == 0)
{
parent = current;
current = current.Left;
}
if (result > 0)
{
parent = current;
current = current.Left;
}
else if (result < 0)
{
parent = current;
current = current.Right;
}
}
if (parent == null)
Root = n;
else
{
result = _comparer.Compare(parent.Value, value);
if (result > 0)
parent.Left = n;
else
parent.Right = n;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我在计算以下行的高度时收到StackoverflowException
if (Parent != null) {
Parent.UpdateHeight();
}
Run Code Online (Sandbox Code Playgroud)
在课堂的Height财产BinaryTreeNode<T>.如果可能的话请建议我解决一些问题.
顺便说一下,非常感谢您的关注,阅读这么长的问题:)
添加节点时,您可以通过递归迭代所有父节点来计算高度。.NET 进程的堆栈空间有限,并且给定一棵大树,您将消耗所有堆栈空间并获得StackOverflowException. 您可以将递归更改为迭代以避免消耗堆栈空间。其他语言(例如函数式语言)能够通过使用称为尾递归的技术进行递归而不消耗堆栈空间。但是,在 C# 中,您必须手动修改代码。
Height以下是和的修改版本,UpdateHeight其中BinaryTreeNode<T>不使用递归:
public int Height {
get { return _height; }
private set { _height = value; }
}
void UpdateHeight() {
var leftHeight = Left != null ? Left.Height + 1 : 0;
var rightHeight = Right != null ? Right.Height + 1 : 0;
var height = Math.Max(leftHeight, rightHeight);
var node = this;
while (node != null) {
node.Height = height;
height += 1;
node = node.Parent;
}
}
Run Code Online (Sandbox Code Playgroud)