递归搜索数组

时间:2015-12-05 01:11:35

标签: java

我需要编写一段代码来测试未排序的数组 a 是否包含值 x ,从开始结束,包括在内。

这是我到目前为止所做的:

boolean linearSearch(int[] a, int x, int start, int end){
  boolean result = false;
  if(a[start]==x){
    result = true;
  } else {
    linearSearch(a,x,++start,end-1);
  }
  return result;
}

这个当前代码抛出一个数组越界异常,我似乎无法弄清楚它为什么不起作用。任何人都可以给我一个正确方向的推动吗?提前谢谢!

4 个答案:

答案 0 :(得分:4)

您遇到的问题是因为您没有进行足够的约束检查。您需要确保的限制是:

  • start小于数组a的长度。
  • end小于数组a的长度。
  • end大于start

即使这样,由于这一行,你的递归也存在问题:

linearSearch(a,x,++start,end-1);

每次递归到此函数时,end值都会递减。这意味着end的原始输入实际上不是最后检查的索引。

进行递归时,最好考虑基本情况。在这种情况下,如果您的数组为空,会发生什么?你必须返回`false:

boolean linearSearch(int[] a, int x, int start, int end){
  if (a.length == 0) { return false; }
  // Do other things
}

我们还需要确定我们是否超过了end点。结果与基本情况相同:

boolean linearSearch(int[] a, int x, int start, int end){
  if ((a.length == 0) || (end == 0)) { return false; }
  // Do other things
}

现在确定阵列的head(第一个元素)是否是start位置是一个问题。如果没有,你跳过检查是否相等,如果是,你执行它:

boolean linearSearch(int[] a, int x, int start, int end){
  if ((a.length == 0) || (end == 0)) { return false; }
  if (start <= 0) { //We are within the correct part of the array
     //check for equality
  } // else recurse without checking
}

检查相等性只是if (head == x)

boolean linearSearch(int[] a, int x, int start, int end){
  if ((a.length == 0) || (end == 0)) { return false; }
  if (start <= 0) { //We are within the correct part of the array
     if (a[0] == x) { return true; }
  } 
  //recurse
}

现在我们检查了基本案例相等案例,我们只需要使用适当的变量进行递归。在这里,我们可以递减startend,因为我们通过删除head将数组的整个长度减少一个。这会减少每个元素的索引以及startend的索引。这可以确保我们的基本情况保持正确。

boolean linearSearch(int[] a, int x, int start, int end){
  if ((a.length == 0) || (end == 0)) { return false; }
  if (start <= 0) { //We are within the correct part of the array
     int head = a[0]; //The head is the first part of an array
     if (head == x) { return true; }
  } 
  // The tail is everything but the head
  int[] tail = Arrays.copyOfRange(a, 1, a.length); //Be careful of off-by-one errors!
  return linearSearch(tail, x, start - 1, end - 1);
}

让我们回顾一下我们的约束:

  • start小于数组a的长度。
    • 如果start大于数组的长度,则返回false,因为我们检查以确保数组中首先包含一些元素。如果我们已经递归到数组为空的点,但start中的值更高,我们仍会返回。
    • 如果start为零或更小,我们将检查相等条件。
  • end小于数组a的长度。
    • 出于同样的原因,end将始终小于数组的末尾或找到的变量。 (我在这里作弊有点因为它不清楚预期的行为是什么。)
  • end大于start
    • 如果end小于start,我们会在false有机会被检查之前返回start

当然,它有助于测试,因此我们将它打包在一个带有main的类中并组合一些有用的测试:

import java.util.Arrays;

public class LinearSearch {

    public static boolean linearSearch(int[] a, int x, int start, int end){
        if ((a.length == 0) || (end == 0)) { return false; }
        if (start <= 0) { //We are within the correct part of the array
            int head = a[0]; //The head is the first part of an array
            if (head == x) { return true; }
        }
        // The tail is everything but the head
        int[] tail = Arrays.copyOfRange(a, 1, (a.length)); //Be careful of off-by-one errors!
        return linearSearch(tail, x, start - 1, end - 1);
    }

    public static final void main(String[] args){
        int[] test_arr1 = {1,2,3,4,5};
        int[] test_arr2 = {3,2,3,1,5};
        int[] test_arr3 = {};

        // Basic success test
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr1, 1, 0, 5));
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr1, 2, 0, 5));
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr1, 3, 0, 5));
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr1, 4, 0, 5));
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr1, 5, 0, 5));

        // Test that order doesn't matter
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr2, 1, 0, 5));
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr2, 2, 0, 5));
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr2, 3, 0, 5));
        System.out.println("Expect false Found " + LinearSearch.linearSearch(test_arr2, 4, 0, 5));
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr2, 5, 0, 5));

        // Test that a sub array works correctly
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr1, 3, 2, 4));
        System.out.println("Expect true Found " + LinearSearch.linearSearch(test_arr1, 4, 2, 4));
        System.out.println("Expect false Found " + LinearSearch.linearSearch(test_arr1, 1, 2, 4));
        System.out.println("Expect false Found " + LinearSearch.linearSearch(test_arr1, 2, 2, 4));
        System.out.println("Expect false Found " + LinearSearch.linearSearch(test_arr1, 5, 2, 4));


        // Test empty array
        System.out.println("Expect false Found " + LinearSearch.linearSearch(test_arr3, 3, 1, 2));

        // Test start after finish
        System.out.println("Expect false Found " + LinearSearch.linearSearch(test_arr1, 3, 2, 1));
    }
}

答案 1 :(得分:1)

分配是递归吗?因为用for循环来做它会容易得多!

但是,在确定错误的方面,考虑使用for循环来实现它可以帮助你弄清楚你的递归实现缺失了什么!

for (int i = 0; i < a.length(), i++) {
    boolean result = false;
    if (a[start] == x) {
        result = true;
    }
}
return result;

在for循环中,中间条件限制循环发生的次数,这基本上就是你在结束时所做的事情。但是,您实际上并未验证结束是否已更改。

End与数组的长度相同,或者只是您希望它停止搜索的某个索引。递归地,结束作为递减计数。一旦end减少到0,意味着它已经检查了数组的每个元素或你指定的任何索引结束。

你需要添加一个额外的条件来检查end == 0(你已经完成了所有元素)。

boolean result = false;
if (end == 0) {
    return result;
}
else if (a[start] == x) {
    result = true;
    **return result;**
}
else {
     // do recursive search again
}

请记住在形成时将逻辑转换为英语:“好的,如果我们已经完成了每个元素的搜索,那么返回。不,好吧,如果我们找到了元素,将结果设置为true并返回。不,搜索下一个元件。

**编辑:有人指出我的答案中有一部分有点不清楚。您收到的越界异常是由于您尝试访问大于数组长度的索引。我提供的解决方案没有检查这个,因为它假定函数的用户正在为函数提供负责任的输入。

处理此案例有两种选择: 1.在第一个条件中添加额外的检查(如果x大于数组的长度减去1或者结束等于0) 2.在方法声明中,添加它会抛出Out of Bounds异常,以便函数的用户负责验证它们的输入和函数的输出。

有许多不同的书籍和材料讨论这两个选项,哪些应该或不应该使用。我会留给你调查并自己决定。**

答案 2 :(得分:0)

为什么不搜索有效的方式?

boolean linearSearch(int[] a, int x){

    for(int y = 0; y < a.length; y++)
        if(a[y] == x)
            return true;

    return false;
}

如果你想在指定的范围内搜索(例如在元素4和元素8之间搜索而不是整个数组),你可以使用这段代码:

boolean linearSearch(int[] a, int x, int start, int end){

    for(int y = start; y < end; y++)
        if(a[y] == x)
           return true;

    return false;
}

至于你的问题,

boolean linearSearch(int[] a, int x, int start, int end){
  boolean result = false;
  if(start == a.length-1)
      return false; // If result still not validated and length limit is reached, return false
  if(a[start] == x){ // When start equals a.length, it throws OFB Exception
    result = true;
  } else{
    linearSearch(a,x,++start,end-1);
  }
  return result;
}

答案 3 :(得分:0)

这有用吗?看起来它会更简单。

boolean linearSearch(int[] a, int x, int start, int end){
    a = Arrays.copyOfRange(a, start, end);
    return Arrays.asList(a).contains(x);
}