我今年早些时候为我的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 :(得分:6)
请注意,Comparable也是一种泛型类型,可通过与其相媲美的类型进行参数化。上面声明mergeSort函数的最常用,类型安全的方法是:
private <T extends Comparable<? super T>> LList<T> mergeSort(LList<T> list) { }
这强制类型T的compareTo方法可以接受类型为T的参数。(理论上,类型可以实现Comparable,但不能与自身相比,如SomeClass implements Comparable<CompletelyDifferentClass>
,所以重要的是对可比较类型参数的要求。然而,在实践中,任何设计良好的可比较类都应至少与其本身相当。)
我们需要<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>
个对象进行排序。
答案 1 :(得分:4)
查看Comparator和Comparable接口。
您的排序方法应该采用Comparator,或者您应该指定&lt; T扩展可比较&gt;以便可以使用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) {
...
}
答案 2 :(得分:3)
好吧,正如你所发现的,你有一个问题。您对列表中对象的所有了解都是它们是Object的实例或其子类之一。你不能真正排序对象。您现在有几个选择:
您拥有的一个选项是对完全没有意义的东西进行排序,例如对象的hashCode。事实上,您可以使用hashCode实现一个完全有效的mergesort,但它基本上没有意义,因为哈希代码实际上并不意味着什么,除了了解排序之外没有特别的理由对它进行排序。
这是一个更好的方法:更改通用列表的规则。现在,列表中的所有内容都必须是某种东西。为什么不改变它,以便它可以是某种实现Comparable
接口的东西?这样,除了如何比较它们之外,您不需要了解任何有关对象的信息。这主要是Java本身如何解决这个问题。 (我建议阅读其收藏内容。)
只需将您的对象从LList<T>
更改为LList<T extends Comparable<T>>
,就可以了!
答案 3 :(得分:1)
您应该使用Comparable界面。
Comparable one = (Comparable)first.headNode.data;
Comparable two = (Comparable)second.headNode.data;
if(one.compareTo(two) < 0)
{
...
}
else
{
...
}
请注意:这非常草率。我没有检查headNode.data实际上是Comparable对象的任何地方。如果是这种情况,我们应该抛出异常。
答案 4 :(得分: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
}
}