7

我需要一组排序的对象,目前正在使用TreeSet. 我的问题是compareTo对象经常会返回0,这意味着这两个对象的顺序保持不变。TreeMapTreeSet默认情况下使用)然后将它们视为同一个对象,这是不正确的。

我可以使用什么替代品TreeMap


用例:我有一组可显示的对象。我想按 Y 坐标对它们进行排序,以便它们以正确的顺序呈现。当然,两个对象很可能具有相同的 Y 坐标。

4

5 回答 5

9

您正在定义一个要比较的标准,但您需要添加额外的标准。

你说:

我有一组可显示的对象。我想按 Y 坐标对它们进行排序,以便它们以正确的顺序呈现。当然,两个对象很可能具有相同的 Y 坐标。

所以,如果两个元素有相同的 Y 坐标,你先放什么?其他标准是什么?

可能是创建时间,也可能是 x 坐标,你只需要定义它:

Map<String,Thing> map = new TreeMap<String,Thing>(new Comparator<Thing>(){
     public int compare( Thing one, Thing two ) {
         int result = one.y - two.y;
         if( result == 0 ) { // same y coordinate use another criteria
             result = one.x - two.x;
             if( result == 0 ) { //still the same? Try another criteria ( maybe creation time
                 return one.creationTime - two.creationTime
             }
          }
          return result;
     }
});

您必须定义一个Thing高于/低于/等于/何时高于另一个Thing。如果其中一个属性与其他属性相同,则可能您不应该移动它们。如果有其他属性比较使用它。

于 2010-06-14T21:16:30.643 回答
4

您遇到的问题是compareTo返回0意味着对象是相等的。同时,您将它们放入一个集合中,这不允许相同元素的多个副本。

要么重写你的compareTo,以便不相等的元素返回不同的值,要么使用类似 a 的东西,java.util.PriorityQueue它允许相等元素的多个副本。

于 2010-06-14T21:39:58.513 回答
1

我以前做过。它是一个有序的多图,它只是一个 List 对象的 TreeMap。像这样..

Map<KeyType, List<ValueType>> mmap = new TreeMap<KeyType, List<ValueType>>();

每次引入新键时,您都需要构造一个新的 LinkedList,因此将其包装在自定义容器类中可能会有所帮助。我会试着找到一些东西。


所以,我很快就把这个自定义容器放在一起(完全未经测试),但它可能是你要找的。请记住,如果您确实在寻找值列表的有序映射,则应该只使用这种类型的容器。如果您的值有一些自然顺序,则应按照其他人的建议使用 TreeSet。

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class MTreeMap<K, V> {

   private final Map<K, List<V>> mmap = new TreeMap<K, List<V>>();
   private int size = 0;

   public MTreeMap() {
   }

   public void clear() {
      mmap.clear();
      size=0;
   }

   public boolean containsKey(K key) {
      return mmap.containsKey(key);
   }

   public List<V> get(K key) {
      return mmap.get(key);
   }

   public boolean isEmpty() {
      return mmap.isEmpty();
   }

   public Set<K> keySet() {
      return mmap.keySet();
   }

   public Collection<List<V>> valueLists() {
      return mmap.values();
   }

   public void put(K key, V value) {

      List<V> vlist = mmap.get(key);
      if (null==vlist) {
         vlist = new LinkedList<V>();
         mmap.put(key, vlist);
      }
      vlist.add(value);
      ++size;
   }

   public List<V> remove(Object key) {
      List<V> vlist = mmap.remove(key);

      if (null!=vlist) { 
         size = size - vlist.size() ;
      }
      return vlist;
   }

   public int size() {
      return size;
   }

   public String toString() {
      return mmap.toString();
   }

}

这是一个基本的测试:

public class TestAnything {

   public static void main(String[] args) {

      MTreeMap<Integer, String> mmap  = new MTreeMap<Integer, String>();

      mmap.put(1, "Value1");
      mmap.put(2, "Value2");
      mmap.put(3, "Value3");
      mmap.put(1, "Value4");
      mmap.put(3, "Value5");
      mmap.put(2, "Value6");
      mmap.put(2, "Value7");

      System.out.println("size (1) = " + mmap.get(1).size());
      System.out.println("size (2) = " + mmap.get(2).size());
      System.out.println("size (3) = " + mmap.get(3).size());
      System.out.println("Total size = " + mmap.size());

      System.out.println(mmap);
   }

}

输出是这样的:

size (1) = 2
size (2) = 3
size (3) = 2
Total size = 7
{1=[Value1, Value4], 2=[Value2, Value6, Value7], 3=[Value3, Value5]}
于 2010-06-14T21:44:48.250 回答
0

我有一个自己的想法,但这更像是一种解决方法

int compare(Object a, Object b) {
   an = a.seq + (a.sortkey << 16); // allowing for 65k items in the set
   bn = b.seq + (a.sortKey << 16);
   return an - bn; // can never remember whether it's supposed to be this or b - a.
}
  • sortKey = 排序中真正重要的内容,例如 Y 坐标
  • seq = 添加到集合时分配给对象的序列号
于 2010-06-14T20:52:32.213 回答
0

使用排序集(例如 TreeSet)时要记住两件重要的事情:

1)它们是集合;同一个集合中不允许有两个相等的元素

2)平等必须与比较机制一致(无论是比较器还是可比较的)

因此,在您的情况下,您应该通过添加一些辅助排序标准来“打破关系”。例如:首先使用 Y 轴,然后是 X,然后是一些唯一的对象标识符。

另请参阅http://eyalsch.wordpress.com/2009/11/23/comparators/

于 2010-06-14T21:25:53.620 回答