【问题标题】:How do I search for a String in an array of Strings using binarySearch or another method?如何使用 binarySearch 或其他方法在字符串数组中搜索字符串?
【发布时间】:2010-12-18 22:44:52
【问题描述】:

使用 binarySearch 永远不会返回正确的索引

int j = Arrays.binarySearch(keys,key);

其中键是String[] 类型,键是String 类型

我阅读了一些关于需要对数组进行排序的内容,但如果是这种情况,我该怎么做呢?

鉴于这一切,我真的只需要知道:

那么如何在一个字符串数组(小于1000)中搜索一个字符串呢?

【问题讨论】:

  • 如果您阅读文档 (j2ee.me/javase/6/docs/api/java/util/…, byte)),它说数组 必须 进行排序并建议使用 sort()。
  • 不是java必须更聪明,你知道
  • 该死,它吃了我的网址:j2ee.me/javase/6/docs/api/java/util/…
  • 如果你搜索的数据没有排序,你怎么会认为它可以进行二分搜索?你认为二分搜索是如何工作的?
  • 如果数组总是很短,那么 bnarySearch 可能会矫枉过正。但是,您应该确定它。数组可能很短,但如果您多次搜索它,在短数组上进行线性搜索可能比在其上进行 binarySearch 慢得多。不要以为因为某事很小,就可以以较慢的方式进行。有时它确实很重要。

标签: java arrays search sorting


【解决方案1】:

java.util.Arrays.sort(myArray);

binarySearch 就是这样设计的——它假定排序是为了更快地找到。

如果您只想在 O(n) 时间内从列表中查找某些内容,请不要使用 BinarySearch,请使用 indexOf。此页面上发布的该算法的所有其他实现都是错误的,因为当数组包含空值或项目不存在时它们会失败。

public static int indexOf(final Object[] array, final Object objectToFind, int startIndex) {
    if (array == null) {
        return -1;
    }
    if (startIndex < 0) {
        startIndex = 0;
    }
    if (objectToFind == null) {
        for (int i = startIndex; i < array.length; i++) {
            if (array[i] == null) {
                return i;
            }
        }
    } else {
        for (int i = startIndex; i < array.length; i++) {
            if (objectToFind.equals(array[i])) {
                return i;
            }
        }
    }
    return -1;
}

【讨论】:

  • 它没有返回正确的索引,因为它假定排序(为了性能)并且你的数组没有排序。
  • 他确实回答了你的问题!它没有找到它,因为数组未排序。要进行二进制搜索,必须对数组进行排序。答案是首先使用 Arrays.sort 对数组进行排序,然后对其调用 binarySearch。
  • 如果你只想要线性搜索,请使用 ArrayUtils 中的 indexOf。
  • 不,它没有。如果您不提供比较器,它会使用元素的“自然顺序”,这意味着它使用 String 从 Comparable 接口实现的 compareTo 方法:java.sun.com/javase/6/docs/api/java/util/…
【解决方案2】:

在 Java 中所有 binarySearch 的重载版本中,没有一个版本接受 String 的参数。但是,有三种类型的 binarySearch 可能对您的情况有所帮助:

static int binarySearch(char[] a, char key); static int binarySearch(Object[] a, Object key); static int binarySearch(T[] a, T key, Comparator c)

【讨论】:

  • 哦,是的,char 特别适合异常
  • @Michael:这是一个字符串数组而不是字符串。
  • Java 中的 String 也不是 char[]。
  • 在这 3 个中只有 Object[],Object 1 是这种情况所需要的。 char[] 不起作用(不是 char[] 中的字符串)并且不需要 Comparator 版本,除非您想更改字符串相互比较的默认顺序(字母顺序)。
  • 现在如果只有一个字符串是一个对象!
【解决方案3】:

来自维基百科:

“在计算机科学中,二分搜索是一种算法,用于通过检查中间位置来定位排序列表中元素的位置,从考虑中排除一半列表,然后对剩余的一半执行搜索。[1 ][2]如果中间元素等于查找的值,则说明位置已经找到;否则,根据该元素大于还是小于中间元素,选择上半部分或下半部分进行搜索。"

所以二分查找的前提是数据是有序的。它必须进行排序,因为它将数组切成两半并查看中间元素。如果中间元素是它正在寻找的东西,它就完成了。如果中间元素较大,则它占用数组的下半部分。如果中间元素较小,则为数组的上半部分。然后重复该过程(查看中间等...),直到找到(或未找到)元素。

如果数据未排序,算法将无法工作。

所以你会做这样的事情:

final String[] data;
final int      index;

data = new String[] { /* init the elements here or however you want to do it */ };
Collections.sort(data);
index = Arrays.binarySearch(data, value);

或者,如果您不想对其进行排序,请进行线性搜索:

int index = -1; // not found

for(int i = 0; i < data.length; i++)
{
    if(data[i].equals(value))
    {
        index = i;
        break; // stop looking
    }
}

为了完整起见,这里有一些完整方法的变体:

// strict one - disallow nulls for everything
public <T> static int linearSearch(final T[] data, final T value)
{
    int index;

    if(data == null)
    {
        throw new IllegalArgumentException("data cannot be null");
    }

    if(value == null)
    {
        throw new IllegalArgumentException("value cannot be null");
    }

    index = -1;

    for(int i = 0; i < data.length; i++)
    {
        if(data[i] == null)
        {
            throw new IllegalArgumentException("data[" + i + "] cannot be null");
        }

        if(data[i].equals(value))
        {
            index = i;
            break; // stop looking
        }
    }    

    return (index);
}

// 允许所有内容为空

public static <T> int linearSearch(final T[] data, final T value)
{
    int index;

    index = -1;

    if(data != null)
    {
        for(int i = 0; i < data.length; i++)
        {
            if(value == null)
            {
                if(data[i] == null)
                {
                    index = i;
                    break;
                }
            } 
            else
            {            
                if(value.equals(data[i]))
                {
                    index = i;
                    break; // stop looking
                }
            }
        }    
    }

    return (index);
}

您可以填写其他变体,例如不允许空数据数组,或不允许在值中出现空值,或不允许在数组中出现空值。 :-)

基于 cmets,这也与 permissive 相同,并且由于您没有编写大部分代码,因此它会比上面的版本更好。如果您希望它是偏执的,并且不允许任何内容为 null,那么您会被上面的偏执版本卡住(并且此版本基本上与其他版本一样快,因为方法调用 (asList) 的开销可能会在运行时消失)。

public static <T> int linearSearch(final T[] data, final T value)
{
    final int index;

    if(data == null)
    {
        index = -1;
    }
    else
    {
        final List<T> list;

        list  = Arrays.asList(data);
        index = list.indexOf(value);
    }

    return (index);
}

【讨论】:

  • +1,但恐怕你的回答可能被置若罔闻。
  • 这里有这么多潜在的敌意,我不敢回应。 :) 在 Java 中内置线性搜索: int index = Arrays.asList(array).indexOf(key);一个额外的分配是一种廉价的传递,所以不要让它欺骗你。它既便宜又容易。
  • 它相当于一个循环,除了没有额外的堆栈变量之外几乎与你的循环相同,因为它们提前返回而不是设置和中断。对我来说,可以这么说,它似乎会消失在噪音中。
  • 不,Arrays.asList() 不会复制数组......它只是将它包装在一个直接传递到数组的薄包装器中。唯一的额外开销是创建该包装器(以及一个方法间接)。
  • 而且它不会因 JVM 而异,因为它被记录为以这种方式运行。
【解决方案4】:

按照您提出的问题正确回答您的问题。使用蛮力

【讨论】:

    【解决方案5】:

    希望对你有帮助

       public int find(String first[], int start, int end, String searchString){
        int mid = start + (end-start)/2;
        // start = 0;
        if(first[mid].compareTo(searchString)==0){
            return mid;
        }
        if(first[mid].compareTo(searchString)> 0){
            return find(first, start, mid-1, searchString);
        }else if(first[mid].compareTo(searchString)< 0){
            return find(first, mid+1, end, searchString);
        }
        return -1;
      }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-22
      • 2022-01-23
      • 2022-01-23
      • 2021-09-15
      • 2015-05-12
      • 2011-07-04
      • 1970-01-01
      相关资源
      最近更新 更多