How to avoid stackoverflow exception?

Here is the situation, I am developing a binary search tree and in each node of the tree I intend to maintain my own height for further balancing the tree when forming the avl tree. I used to have an iterative approach to calculate the height of a node when balancing a tree, as shown below.

(The following code belongs to a class AVLTree<T>that is a child class 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;            
        }

But it incurred a lot of overhead.

AVL tree performance in C #

So, I went to store the height value in each node during input in BinarySearchTree<T>. Now, during balancing, I can avoid this iteration, and I am gaining the desired performance in 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;
        }

    }

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;
            }
        }
    }

StackoverflowException

if (Parent != null) {
                    Parent.UpdateHeight();
                } 

Height BinaryTreeNode<T>. , .

, , :)

+5
4

node, , . .NET StackOverflowException. , . , , , , , . # .

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;
  }
}
+2

. il, .

:

.... IL_0002:

.

IL_0003: ...

IL_0008: ret

:

ilasm C:\test.il/out=C:\TestTail.exe

(, , , , )

, , .

, , msbuild, .

0

, , ,

public int Height
        {
            get { return _height; }
            protected internal set
            {
                _height = value;                                
            }
        }

        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;

            var parent = Parent;
            while (parent != null) {
                parent.Height++;
                parent = parent.Parent;             
            }           

        }

, , , .

0

If you insert large amounts of data at a time, I would think that you would better insert the batch data without calling Parent.UpdateHeight, then go through the tree, setting the height as you move.

Adding future nodes I would walk along the tree, starting from the root, increasing height as I move.

0
source

All Articles