开发者

Which to use ? IComparable generic or non-generic in this scenario

I have a generic BST and a dataItem class to act as treeNode's value.

public class BinarySearchTree<T> : ICollection<T>  where T : IComparable
{

}

public class EnglishDictionaryWord
    : IComparer<EnglishDictionaryWord>, IComparable<EnglishDictionaryWord>
{
    public EnglishDictionaryWord(string word, WordCompareType type)
    {
        Word = word;
        Length = Word.Length;
        _compareType = type;
    }

    public int Compare(EnglishDictionaryWord x, EnglishDictionaryWord y)
    {
        if (_compareType == WordCompareType.Length)
            return new WordLengthComparer().Compare(x, y);
        else if (_compareType == WordCompareType.Lexical)
            return new WordLexicalComparer().Compare(x, y);
        else
            throw new InvalidOperationException("Unsupported Comparison type");
    }

    public int CompareTo(EnglishDictionaryWord obj)
    {
        return Compare(this, obj);
    }
} 

public class WordLengthComparer : IComparer<EnglishDictionaryWord>
{
    public WordLengthComparer()
    {

    }
    public int Compare(Eng开发者_C百科lishDictionaryWord x, EnglishDictionaryWord y)
    {
        return x.Length - y.Length;
    }
}

and similar Lexical comparer class.

Now when i try to use:

BinarySearchTree<EnglishDictionaryWord> _tree = 
    new BinarySearchTree<EnglishDictionaryWord>();

I get compile error:

The type 'DsLib.EnglishDictionaryWord' cannot be used as type parameter 'T' in the generic type or method 'DsLib.BinarySearchTree'. There is no implicit reference conversion from 'DsLib.EnglishDictionaryWord' to 'System.IComparable'.

If I try to make

public class BinarySearchTree<T> : ICollection<T>  where T : IComparable<T>

then I get this compile error about boxing conversion unavailable.

The type 'T' cannot be used as type parameter 'T' in the generic type or method 'DsLib.BinaryTreeNode'. There is no boxing conversion or type parameter conversion from 'T' to 'System.IComparable'.

I have 2 questions:

(1). I am confused on the generics implementation. Can some one detail how to correct it ? and general pattern to avoid such errors in future. When to use IComparable<T> and when IComparable.

(2). Is this comparer pattern correct, having comparer inside the dataitem class? Because user will provide new EnglishWord to be inserted into tree. He can potentially be using different comparer for each word. Then it will break the Tree.

EDIT: Added BSTNode class code

public class BinaryTreeNode<T> where T : IComparable
{
    public BinaryTreeNode(T value)
    {
        Value = value;
    }

    public T Value { get; protected internal set; }
    public BinaryTreeNode<T> Right { get; protected internal set; }
    public BinaryTreeNode<T> Left { get; protected internal set; }
    public BinaryTreeNode<T> Parent { get; protected internal set; }

    public int Height { get; protected internal set; }
}


I tried your code with the following definitions:

  public class BinarySearchTree<T>
      : ICollection<T>
      where T : IComparable<T>

  public class EnglishDictionaryWord
      : IComparer<EnglishDictionaryWord>,
        IComparable<EnglishDictionaryWord>

  public class WordLengthComparer
      : IComparer<EnglishDictionaryWord>

and it works just fine - it compiles, executes etc... (.NET 4.0, c#):

 BinarySearchTree<EnglishDictionaryWord> _tree = 
     new BinarySearchTree<EnglishDictionaryWord>();

And to answer your other questions:

  1. You should always favor IComparable<T> instead of IComparable. It's faster and less prone to errors (no casting/boxing/unboxing) etc... As for your question: Why is it required? it's simple - the IComparable<T> and IComparable are different types (they have similar names, but don't let that confuse you - the types are different). So, you simply need to put the same type wherever referenced.

  2. The data that's inserted in the tree should have comparing logic. When you define the tree, you specify exactly what types of items it will work with - so for as long as that object lives, you can't add some completely different type into it. E.g., if you defined:

    BinarySearchTree<EnglishDictionaryWord> _tree;

you cannot add to _tree something else, like SpanglishDictionaryWord, so the tree does keep it's structure correctly, because only items of EnglishDictionaryWord are added, and they have defined structure and comparing logic that's consistent.

EDIT I just saw you have an "Has" comparer logic, instead of pure "Is" comparable. That should be fixed (remove the reference to the comparer from within data items) - if not, you're right - the tree might get broken...

EDIT2 If you need the data items to have flexible comparing logic (ie. change the way they are compared, which is strange so think about it), then the BST has to have a reference to the instance of the comparer you intend to use with it: either put the items that wrap the comparer and the actual item, or put the Comparer of items as a property of BST and use that on each data item when deciding which branch to go to.


You need to change BinaryTreeNode, too:

public class BinaryTreeNode<T> where T : IComparable<T>


It compiles if i change to IComparable<T> everywhere in Tree related classes/methods. Why this is required?

IComparable<T> does not inherit from IComparable.

and the 2nd question ?

You're right - if different items have different sort types, the list will malfunction. A better pattern is to have the type own a single default ordering behavior, and then allow the collection to accept and use alternate IComparers. To see this in action, examine the overloads of Enumerable.OrderBy

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜