2009-04-09 118 views
1

今年早些时候,我为我的java类写了一个链表实现。这是一个名为LList的通用类。我们现在必须写出实验室的合并排序算法。我没有创建一个采用Ints的新List实现,而是决定重用我之前创建的通用列表。比较通用列表中的元素

问题是如何比较两个通用对象? 的Java不会让我这样做

if(first.headNode.data > second.headNode.data) 

所以,我的问题是,是他们实现某种比较函数将在任何类型的数据的工作方式?我尝试了以下内容:

 String one, two; 
     one = first.headNode.data.toString(); 
     two = second.headNode.data.toString(); 
     if(first.headNode.data.compareTo(second.headNode.data) < 0) { 
      result.add(first.headNode.data); 
      // remove head node. remove() takes care of list size. 
      first.remove(1); 
     } else { 
      // If compareTo returns 0 or higher, second.headNode is lower or 
      // equal to first.headNode. So it's safe to update the result 
      // list 
      result.add(second.headNode.data); 
      second.remove(1); 
     } 

哪个甚至不能正常工作。我用数字6和12进行了测试,上面在结果列表中增加了12。

相关的东西:

private LList<T> mergeSort(LList<T> list) { 
    LList<T> first = new LList(); 
    LList<T> second = new LList(); 
    if (list.length() == 1) { 
     return list; 
    } 

    int middle = list.length()/2; 
    second.headNode = list.getNodeAt(middle + 1); 
    second.length = list.length() - (middle); 
    // Set first half to full list, then remove the "second" half. 
    first.headNode = list.headNode; 
    first.length = middle; 
    first.getNodeAt(middle).next = null; 

    // Get the splitted halves. 
    first = mergeSort(first); 
    second = mergeSort(second); 
    return merge(first, second); 
} 

private LList<T> merge(LList<T> first, LList<T> second) { 
    LList<T> result = new LList(); 

    while((first.length > 0) && (second.length > 0)) { 
     // Ok, lets force toString to compare stuff since generics are a pain. 
     String one, two; 
     one = first.headNode.data.toString(); 
     two = second.headNode.data.toString(); 
     if(one.compareTo(two)) < 0) { 
      result.add(first.headNode.data); 
      // remove head node. remove() takes care of list size. 
      first.remove(1); 
     } else { 
      // If compareTo returns 0 or higher, second.headNode is lower or 
      // equal to first.headNode. So it's safe to update the result 
      // list 
      result.add(second.headNode.data); 
      second.remove(1); 
     } 
    } 
    return result; 
} 

注意:整个LLIST类可以找到[这里](http://rapidshare.com/files/219112739/LList.java.html MD5:BDA8217D0756CC171032FDBDE1539478)

+0

如果您想“欺骗”,请查看Java源代码,以获取类似Collections.sort()的内容。当你安装JDK时,应该有一个选项来安装源代码。然后在安装目录中会有一个src.jar文件。 .jar文件可以重命名为.zip并在WinZip中打开。 – Kip 2009-04-09 02:18:24

回答

4

看看ComparatorComparable接口。

您的排序方法应采取Comparator或您应指定< T扩展Comparable>,以便可以使用Comparable接口。

public void sort(Comparable<T> comparator) { 
    sort(SortType.MERGE, comparator); 
} 
.... 
private LList<T> merge(LList<T> first, LList<T> second) { 
    ... 
     if(comparator.compare(first.headNode.data, second.headNode.data) < 0) { 
    ... 
} 
1

你应该利用Comparable接口。

Comparable one = (Comparable)first.headNode.data; 
Comparable two = (Comparable)second.headNode.data; 

if(one.compareTo(two) < 0) 
{ 
    ... 
} 
else 
{ 
    ... 
} 

请注意:这是相当马虎。我没有在任何地方检查headNode.data实际上是一个Comparable对象。如果是这样,我们应该真的抛出异常。

3

那么,正如你发现的那样,你有一个问题。你所知道的列表中的对象是它们是Object或它的一个子类的实例。你不能真正对对象进行排序。你现在有几个选择:

你有一个选择是排序一些完全没有意义的东西,比如对象的hashCode。事实上,你可以使用hashCode来实现一个完全有效的mergesort,但它在很大程度上是毫无意义的,因为哈希码实际上并不意味着什么,除了了解排序之外没有什么特别的理由要对它进行排序。

下面是一个更好的方法:更改通用列表的规则。现在,你列表中的所有东西都必须是某种东西。为什么不改变它,以便它可以是某种实现接口的任何事物?这样,除了如何比较对象之外,您不需要了解任何有关对象的信息。这主要是Java本身如何解决这个问题。 (我建议阅读其收藏的东西)。

只需将您的对象从LList<T>改为LList<T extends Comparable<T>>,您就可以轻松前往!

+0

完美的工作。谢谢。在得到Comparable之后,我只是对mergeSort进行了一些更改(应该或不应该在那里的事情),现在可以正确排序。谢谢 – 2009-04-09 02:42:29

+0

很高兴能帮到你!另外 - 我喜欢你的笑人图标:) – 2009-04-09 02:49:44

1

在我创建的C#框架中为我工作的东西。为类型化对象创建比较对象,并使用反射来确定列表正在排序的属性的值。根据需要调整:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 

namespace BOCL 
{ 
    /// <summary> 
    /// Provides a comparer for collections of BOCL objects so they can be compared on any property 
    /// </summary> 
    /// <typeparam name="T">The type of BOCL object to compare</typeparam> 
    public class BusinessBaseComparer<T> : IComparer<T> where T : BusinessBase<T>, new() 
    { 
    #region Constructors 

    /// <summary> 
    /// Provides a default constructor for the comparer 
    /// </summary> 
    protected BusinessBaseComparer() 
    { 
     //An instance of the business base comparer must be declared with at least one argument to be of any use 
    } 

    /// <summary> 
    /// Build this comparer sorting on a particular property ascending 
    /// </summary> 
    /// <param name="property">The property on which the sort should be applied</param> 
    public BusinessBaseComparer(PropertyDescriptor property) 
    { 
     m_SortProperty = property; 
    } 

    /// <summary> 
    /// Build this comparer sorting on a particular property 
    /// </summary> 
    /// <param name="property">The property on which the sort should be applied</param> 
    /// <param name="direction">The direction to which the sort should be applied</param> 
    public BusinessBaseComparer(PropertyDescriptor property, ListSortDirection direction) 
    { 
     m_SortProperty = property; 
     m_SortDirection = direction; 
    } 

    #endregion 

    #region SortProperty 

    private PropertyDescriptor m_SortProperty = null; 

    /// <summary> 
    /// The property on which the type is to be sorted. If the property is not found, the objects are deemed equal 
    /// </summary> 
    protected PropertyDescriptor SortProperty 
    { 
     get { return m_SortProperty; } 
    } 

    #endregion 

    #region SortDirection 

    private ListSortDirection m_SortDirection = ListSortDirection.Ascending; 

    /// <summary> 
    /// The direction in which the type is to be sorted 
    /// </summary> 
    protected ListSortDirection SortDirection 
    { 
     get { return m_SortDirection; } 
    } 

    #endregion 

    #region IComparer<T> Members 

    /// <summary> 
    /// Performs comparison between to BOCL objects 
    /// </summary> 
    /// <param name="x">The first object to compare</param> 
    /// <param name="y">The second object to compare</param> 
    /// <returns>The result of the comparison</returns> 
    public int Compare(T x, T y) 
    { 
     if (SortProperty == null) 
     return 0; //we didn't find the property we were supposed to sort on 

     //set up to get the value of the objects we are comparing against 
     IComparable xValue = null; 
     IComparable yValue = null; 

     try 
     { 
     //now get the value for the x object and value for the y object 
     //as something we can compare against 
     xValue = (IComparable)SortProperty.GetValue(x); 
     yValue = (IComparable)SortProperty.GetValue(y); 

     //if either property came back null 
     if (xValue == null || yValue == null) 
      return 0; //treat them as the same 
     } 
     catch (InvalidCastException) 
     { 
     return 0; //ran into a proplem trying to convert the object into something we could compare against 
     } 


     if (SortDirection == ListSortDirection.Ascending) 
     return xValue.CompareTo(yValue); 
     else 
     return yValue.CompareTo(xValue); 
    } 

    #endregion 
    } 
} 
6

请注意,Comparable也是一个泛型类型,它可以通过它可比较的类型进行参数化。声明以上的归并功能最一般的,类型安全的方式是:

private <T extends Comparable<? super T>> LList<T> mergeSort(LList<T> list) { } 

这加强了该类型T的compareTo方法可以接受类型T的参数(从理论上讲,一种可以实现相媲美,但不像SomeClass implements Comparable<CompletelyDifferentClass>那样,所以对Comparable类型参数有要求是很重要的,但实际上,任何精心设计的Comparable类应该至少可以与它本身相媲美。)

我们需要<T extends Comparable<? super T>>而不是仅仅是<T extends Comparable<T>>,因为如果类型T的compareTo方法接受比T更通用的类型,它仍然能够接受类型T的参数。这很重要,因为如果您有一个实现Comparable<A>的类A,然后你有一个扩展A的子类B,B不能实现Comparable<B>,因为B已经实现Comparable<A>,继承自A,并且一个类不能实现一个接口两次。所以如果我们要求上面的<T extends Comparable<T>>,B不会满足它,我们将无法排序LList<B>对象。