Search code examples
c#oopinterval-tree

Extend a class without changing a base algorithm implementation?


I'm writing an interval tree in C#. What I'd like to do is just extend an existing binary search tree to store intervals and not have to rewrite the core functionality (add, get, delete).

Inside the BST, I have a Node class:

protected class Node 
{
    public KeyValuePair<TKey, TVal> Data;
    public Node Left, Right;

    public Node(KeyValuePair<TKey, TVal> data,
        Node left = null, Node right = null)
    {
        Data = data;
        Left = left; Right = right;
    }
}

And inside the interval tree, I have an IntervalNode class that extends Node:

private class IntervalNode : Node
{
    public Interval<TInterval> Interval;
    public override string ToString()
    {
        return string.Format("A={0}, B={1}", Interval.A, Interval.B);
    }

    public IntervalNode(KeyValuePair<TInterval, TVal> data, 
        Node left = null, Node right = null)
        : base(data, left, right)
    {
    }
}

The issue I'm running into is trying to store IntervalNode in the tree rather than Node. Is there any way I can now use the existing base implementations of Add with IntervalNode?

protected Node Add(Node root, KeyValuePair<TKey, TVal> data)
{
    // regular binary search tree insert
} 

I guess what I'd like to be able to do is something like this:

public void Add(Interval<TInterval> intvl, TVal val)
{
    _root = Add((Node)_root, new KeyValuePair<TInterval, TVal>(intvl.A, val));
    IntervalNode inserted = (IntervalNode)Get(_root, intvl.A);
    inserted.Interval = intvl;
}

// tree should store IntervalNodes, not Nodes
private IntervalNode _root;

Solution

  • Your example code won't compile, but here is what I think you are trying to get at:

    protected class Node
        {
            public KeyValuePair<TKey, TVal> Data;
            public Node Left, Right;
    
            public Node(KeyValuePair<TKey, TVal> data,
                Node left = null, Node right = null)
            {
                Data = data;
                Left = left; Right = right;
            }
    
            public virtual void Add(Node root, KeyValuePair<TKey, TVal> data)
            {
                //Do whatever
            }
        }
    

    Then in the derived class:

    private class IntervalNode: Node
        {
            public Interval<TInterval> Interval;
            public override string ToString()
            {
                return string.Format("A={0}, B={1}", Interval.A, Interval.B);
            }
    
            public IntervalNode(KeyValuePair<TInterval, TVal> data, 
                Node left = null, Node right = null)
                : base(data, left, right)
            {
            }
    
            public override void Add(Node root, KeyValuePair<TInterval, TVal> data)
            {
                //Do whatever you need to, then
                base.Add(root, data);
            }
        }
    

    You'll need to fix the generics problem you have but you should be able to see the point.

    Since IntervalNode is a Node, you can store it in the same place that the base class does, there isn't a need to cast it or to separate the storage out. That is a nice part about inheritance.