【问题标题】:Java Collection - Top and Bottom n elementsJava 集合 - 顶部和底部 n 个元素
【发布时间】:2012-07-23 03:31:21
【问题描述】:

我有一个相当独特的要求,我的集合中应该只包含 Top 和 Bottom n 元素。这些元素是可比较的,并且集合本身是有界的,这意味着评估是在向集合添加条目时完成的。

例如,当以下一组值被插入到“Top and Bottom 10”集合中时

5、15、10、1、12、8、11、2、16、14、9、3、20、7

集合应仅包含以下内容

20、16、15、14、12、7、5、3、2、1

我正在考虑维护 2 个由 n/2 个元素组成的 SortedSet,然后在最后合并它们,但是这种方法并不干净,需要在使用结果之前进行合并步骤。

只是希望有人能更好地解决这个问题。

【问题讨论】:

  • 您可能只需要一个 Treeset - 子集方法可以让您轻松访问仅顶部/底部 5 和较低/较高的方法来测试包含。 + pollFirst/Last 删除正确的项目。但是您仍然需要对其进行编码。
  • 我确实通过了 TreeSet API(子集和尾集),但由于大多数操作都是基于元素而不是索引,我无法弄清楚如何实现。
  • TreeSet 是排序的,所以如果大小为 10,你知道子集(0,4)是前 5,子集(5,9)是后 5(反之亦然,im不确定)
  • assylias 可能是我的问题不清楚。将插入到集合中的条目数量很大(约 100,000),但在任何给定时间我希望它只保留前 N 或后 N。其他将被丢弃。
  • 我的想法是使用 TreeSet 并在添加检查大小之前,如果 size

标签: java sorting collections filtering


【解决方案1】:

1.您想要排序和唯一性,请使用TreeSet from java.util.Collection您的数据将自动按自然顺序排序并保持唯一性

2. 使用Collections.reverse()根据需要反转集合...

【讨论】:

  • 我确实有一个 TreeSet 并且元素是根据我自己的比较实现进行排序的,但是这个集合需要限制为 n 个元素并且不包含超过其必要的元素。主要是为了优化内存,因为插入的元素数量会很高。
  • 在插入数据的时候用逻辑来处理.. like if (mtree.size()>n){ // 已经达到极限} else { mtree.add(值)}
  • 通过这个我能够实现“Top N”或“Bottom N”,但不适用于“Top and Bottom N”场景..
  • 我还没有得到清晰的图片...你能说明一下吗..然后我可以很容易地为你编码
  • Vivek,就像我想象的那样使用 TreeSet; Top N - 从尾部丢弃。底部 N - 从头部丢弃。顶部和底部 N - 从中​​间丢弃。现在的问题仅仅是如何从 Treeset 的中间丢弃。例如。在 Top & Bottom 10 场景中,当添加第 11 个元素时,必须删除第 6 个元素。
【解决方案2】:

因为我喜欢在这样的周日下午写文集,

import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import org.junit.Test;

public class TopBottom {

    public int[] top;
    public int[] bottom;

    public TopBottom(int size) {
        top = new int[size];
        Arrays.fill(top, Integer.MIN_VALUE);
        bottom = new int[size];
        Arrays.fill(bottom, Integer.MAX_VALUE);
    }

    public void add(int element) {
        int n = Arrays.binarySearch(top, element);
        if (n < -1) {
            System.arraycopy(top, 1, top, 0, -2 - n);
            top[-2 - n] = element;
        }
        int m = Arrays.binarySearch(bottom, element);
        if (m < 0 && bottom.length >= -m) {
            System.arraycopy(bottom, -1 - m, bottom, 0 - m, bottom.length + m);
            bottom[-1 - m] = element;
        }
    }

    public void add(int... elements) {
        for (int each: elements) {
            add(each);
        }
    }

    public String toString() {
        StringBuilder buf = new StringBuilder();
        buf.append('[');
        for (int each: bottom) {
            buf.append(each);
            buf.append(", ");
        }
        for (int each: top) {
            buf.append(each);
            buf.append(", ");
        }
        buf.setLength(buf.length() - 2);
        buf.append("]");
        return buf.toString();
    }

    public static class Examples {

        @Test
        public void shouldHoldOnlyTopFiveAndBottomFive() {
            TopBottom tp = new TopBottom(5);
            tp.add(5, 15, 10, 1, 12, 8, 11, 2, 16, 14, 9, 3, 20, 7);
            assertEquals("[1, 2, 3, 5, 7, 12, 14, 15, 16, 20]", tp.toString());
        }

    }

}

它使用Arrays#binarySearch 方法,如果缺少元素,该方法(除了查找现有元素外)将插入点返回到排序列表中。插入点返回为(-1-index),因此检查nm 是否为负数,然后使用-1-n 形式的表达式来获取插入点或前后点。

【讨论】:

  • 我以不同的方式解决了这个问题;不知道哪种解决方案会更快。我的实现;对于每个插入,将 TreeSet 元素转换为数组;然后查找位置 (n/2) 处的元素并将其从 TreeSet 中删除。基本上从 Treeset 中删除中间元素。性能应该很好,因为我们正在处理树中有限 (n) 个元素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-26
  • 2021-03-30
  • 2011-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多