2009-04-09 115 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>對象。