如何有效地搜索多个数组中的项目?

时间:2014-02-27 17:07:10

标签: java algorithm

目前我有5个已排序的数组,它们的大小均为3.将来,它可以是10000个排序数组和100000个元素。我试图在5个阵列(或其前身,如果它不存在)中的每个阵列中搜索单个元素。

显然,我可以单独搜索每个数组,这将导致O(k log n),其中k是排序数组的数量。

我们可以在O(log n)中进行吗?我认为可能有一些更好的方法,因为我们正在进行相同的搜索k次

下面是我的代码,它将采用O(k log n) -

public class SearchItem {

    private List<List<Integer>> dataInput;

    public SearchItem(final List<List<Integer>> inputs) {
        dataInput = new ArrayList<List<Integer>>();
        for (List<Integer> input : inputs) {
            dataInput.add(new ArrayList<Integer>(input));
        }
    }

    public List<Integer> getItem(final Integer x) {
        List<Integer> outputs = new ArrayList<Integer>();
        for (List<Integer> data : dataInput) {
            int i = Collections.binarySearch(data, x); // binary searching the item
            if (i < 0)
                i = -(i + 1);
            outputs.add(i == data.size() ? null : data.get(i));
        }
        return outputs;
    }

    public static void main(String[] args) {
        List<List<Integer>> lists = new ArrayList<List<Integer>>();

        List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(3, 4, 6));
        List<Integer> list2 = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
        List<Integer> list3 = new ArrayList<Integer>(Arrays.asList(2, 3, 6));
        List<Integer> list4 = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
        List<Integer> list5 = new ArrayList<Integer>(Arrays.asList(4, 8, 13));

        lists.add(list1);
        lists.add(list2);
        lists.add(list3);
        lists.add(list4);
        lists.add(list5);

        SearchItem search = new SearchItem(lists);

        List<Integer> dataOuput = search.getItem(3);

        System.out.println(dataOuput);
    }

}

知道如何在O(log n)中实现这一目标吗?我想保留SearchItem构造函数输入参数,因为它将接受List of List ..

可能有一些有效的方法可以做到这一点..我们可能需要将数组合并在一起吗?

3 个答案:

答案 0 :(得分:0)

您可以比O(n log n)更快地执行此操作,但这需要您将数组(将它们全部添加在一起)合并到TreeSet(或具有虚拟值的TreeMap)中。添加操作将具有复杂度O(n)。然后提取元素将具有复杂度O(1) - 这仅在您使用TreeSet或TreeMap或类似数据结构时。因此,在这种情况下的总时间复杂度将是O(n) - 比O(n log n)快但比O(log n)慢。我不能想到一次性对整个数组进行二进制搜索而不以某种方式合并它们。

粗略的算法是:

HashSet<Integer> set = new HashSet<Integer>();
for i = 0 to 4 // number_of_arrays = 5 in your case
   for j = 0 to 2 // for Array of length 3 as you mentioned
   // Depending on how you have your arrays this will change
      set.add(a[i][j]); // 2 dimensional arrays are an array of arrays
boolean flag = set.contains(element); // true if element present
if (flag == true)
   // do logic for element present
else
   // do logic for element not present

答案 1 :(得分:0)

不确定这是否会使它更快,但是当您搜索多次出现时,也许您可​​以将TreeMap保留为索引,其中您将元素作为键,并将数组的索引作为键。值:map.get(3);将返回一个包含0,1,2,3,4的列表,map.get(13);将返回5.如果不同列表中元素的出现次数较少,这将为您节省很多二进制搜索(13例)。

答案 2 :(得分:0)

将工作负载从搜索转移到数据加载的工作类。

公共类TestSearch {

public TestSearch(List<List<Integer>> dataInput) {
    this.dataInput = dataInput;
    int searchResultIndex = 0;
    minSearchItem = Integer.MAX_VALUE;
    maxSearchItem = Integer.MIN_VALUE;
    for (List<Integer> list : dataInput) {
        for (Integer item : list) {
            if (item > maxSearchItem ) {
                maxSearchItem = item;
            }
            if (item < minSearchItem) {
                minSearchItem = item;
            }
            List searchResultsList = searchResults.get(item);
            if (searchResultsList == null)  {
                searchResultsList = Arrays.asList(null,null,null,null,null);
                searchResults.put(item,searchResultsList);
            }
            if (minimums.get(searchResultIndex) == null) {
                minimums.set(searchResultIndex, item);
            }
            for (int key : searchResults.keySet())  {
                if (key < item && searchResults.get(key).get(searchResultIndex) == null) {
                    searchResults.get(key).set(searchResultIndex,item);
                }
            }
            searchResultsList.set(searchResultIndex,item);
        }
        searchResultIndex++;
    }
}

private List<List<Integer>> dataInput;
private List<Integer> minimums =Arrays.asList(null,null,null,null,null);
private Integer minSearchItem;
private Integer maxSearchItem;
private Map<Integer,List<Integer>> searchResults = new HashMap<Integer,List<Integer>>(15);


public List<Integer> getItem(final Integer x) {
    if (x <= minSearchItem) {
        return minimums;
    }
    if (x > maxSearchItem) {
        return Arrays.asList(null,null,null,null,null);
    }
    List<Integer>outputs =  searchResults.get(x);
    int nextKey = x + 1;
    while (outputs ==  null) {
        outputs = searchResults.get(nextKey);
        nextKey++;
    }
    return outputs;
}

public static void main(String[] args) {
    List<List<Integer>> lists = new ArrayList<List<Integer>>();

    List<Integer> list1 = new ArrayList<Integer>(Arrays.asList(3, 4, 6));
    List<Integer> list2 = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
    List<Integer> list3 = new ArrayList<Integer>(Arrays.asList(2, 3, 6));
    List<Integer> list4 = new ArrayList<Integer>(Arrays.asList(1, 2, 3));
    List<Integer> list5 = new ArrayList<Integer>(Arrays.asList(4, 8, 13));

    lists.add(list1);
    lists.add(list2);
    lists.add(list3);
    lists.add(list4);
    lists.add(list5);

    TestSearch search = new TestSearch(lists);

    List<Integer> dataOuput = search.getItem(0);

    System.out.println(dataOuput);
}

}