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:
You should always favor
IComparable<T>
instead ofIComparable
. It's faster and less prone to errors (no casting/boxing/unboxing) etc... As for your question: Why is it required? it's simple - theIComparable<T>
andIComparable
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.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
精彩评论