如何避免此stackoverflow异常?

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)

但它带来了很多性能开销.

C#中AVL树的性能

所以我在插入时在每个节点中存储高度值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>.如果可能的话请建议我解决一些问题.

顺便说一下,非常感谢您的关注,阅读这么长的问题:)

Mar*_*age 2

添加节点时,您可以通过递归迭代所有父节点来计算高度。.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)