Java版的数据结构和算法(一)

PS:本文系转载文章,阅读原文可读性会更好,文章末尾有原文链接

ps:本篇文章写线性查找算法、二分查找算法和插值查找算法。

1、线性查找算法

线性查找算法是最简单的查找算法,它的思路就是:对一组有序或者无序的序列进行遍历,逐个比较,如果要查找的值和序列中的某个值相等,那么证明已经找到,就返回这个值在序列中的索引;如果要查找的值遍历完序列后还是没有一个与之相等的值,那么就返回 -1。

我们来举个例子,假设有一个 int 类型数组 a={2,4,3,5,1,8,9},我们从这个数组 a 中找 1 和 0,那么代码如下所示:

public class Test8 {

/**

  • @param args
    */
    public static void main(String[] args) {
    int[] a = {2,4,3,5,1,8,9};
    int result = linearSearch(a,1);
    int result2 = linearSearch(a,0);
    System.out.println(result == -1 ? "没有找到1" : ("1在数组a中的位置为:" + result));
    System.out.println(result2 == -1 ? "没有找到0" : ("0在数组a中的位置为:" + result2));
    }

/**

  • @param arr 要查找的数组
  • @param findVal 要查找的值
  • @return 返回对应值在数组中的下标,如果没有返回 -1
    */
    public static int linearSearch(int[] arr, int findVal) {
    int result = -1;
    if (arr == null || arr.length <= 0) {
    result = -1;
    } else {
    for (int i = 0; i < arr.length; i++) {

    if (arr[i] == findVal) {
      result = i;
      break;
     }

    }
    }
    return result;
    }

}

运行结果如下所示:

1在数组a中的位置为:4
没有找到0

2、二分查找算法

二分查找算法又叫折半查找算法,能够进行二分查找算法是有要求的:它是一个有序数列且存放是按照从小到大进行的。

我们用 start 表示数列起始位置下标,用 end 表示数列终止位置下标,mid 表示数列中间位置下标,用 findVal 表示待查找元素,用 a 表示数组名称;在已经排好序的序列中,通过 mid=(start+end)/2 计算出中间位置,通过 findVal 与 mid 进行比较,如果相等,那么就证明已经找到;如果 findVal 比 a[mid] 小,那么将 end = mid -1,也就是将 end 移动到 mid 左边一个位置,并且重新计算 mid;如果比 a[mid] 大,那么将 start = mid + 1 ,也就是将 start 移动到 mid 右边一个位置,并且重新计算 mid;一直循环查找,直到 start > end,证明没找到对应的元素,停止循环。

我们举个例子再详细分析一下,假设我有一个有序数列且大小都是从小到大排列的数组 a={1, 2, 3, 4, 5, 6, 7, 8, 9, 10},一开始 start = 0,end = 9,mid = (start + end) / 2 = (0 + 9) / 2 = 4,a[mid] = a[4] = 5 。

2、1 假设查找 4

(1)因为 4 < a[mid] = a[4] = 5,所以将 end 移动到 mid 左边一个位置,end = mid - 1 = 4 - 1 = 3 。

(2)重新计算 mid,mid = (start + end)/ 2 = (0 + 3) / 2 = 1;因为 4 > a[mid] = a[1] = 2,所以将 start 移动到 mid 右边一个位置,start = mid + 1 = 1 + 1 = 2 。

(3)重新计算 mid,mid = (start + end) / 2 = (2 + 3) / 2 = 2;因为 4 > a[mid] = a[2] = 3,所以将 start 移动到 mid 右边一个位置,start = mid + 1 = 2 + 1 = 3 。

(4)重新计算 mid,mid = (start + end) / 2 = (3 + 3) / 2 = 3;因为 4 = a[mid] = a[3] = 4,所以已经找到,退出循环。

2、2 假设查找 11

(1)因为 11 > a[mid] = a[4] = 5,所以将 start 移动到 mid 右边一个位置,start = mid + 1 = 4 + 1 = 5 。

(2)重新计算 mid,mid = (start + end)/ 2 = (5 + 9) / 2 = 7;因为 11 > a[mid] = a[7] = 8,所以将 start 移动到 mid 右边一个位置,start = mid + 1 = 7 + 1 = 8 。

(3)重新计算 mid,mid = (start + end)/ 2 = (8 + 9) / 2 = 8;因为 11 > a[mid] = a[8] = 9,所以将 start 移动到 mid 右边一个位置,start = mid + 1 = 8 + 1 = 9 。

(4)重新计算 mid,mid = (start + end)/ 2 = (9 + 9) / 2 = 9;因为 11 > a[mid] = a[9] = 10,所以将 start 移动到 mid 右边一个位置,start = mid + 1 = 9 + 1 = 10 。

(5)start = 10,end = 9,start > end,说明没有找到,所以退出循环。

我们用代码实现一下:

public class Test8 {

public static void main(String[] args) {

int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
binarySearch(a, 4);
binarySearch(a, 11);

}

private static int binarySearch(int[] a, int findValue) {

int result = -1;
if (a != null && a.length > 0) {
  int mid = 0;
  int start = 0;
  int end = a.length - 1;
  while (true) {
    mid = (start + end) / 2;
    if (start > end) {
      System.out.println("未从数组a中找到" + findValue);
      break;
    } else if (findValue > a[mid]) {
      start = mid + 1;
    } else if (findValue < a[mid]) {
      end = mid - 1;
    } else {
      result = mid;
      System.out.println("从数组a中已经找到了" + findValue + ",它在第"
          + result + "个位置");
      break;
    }
  }
} else {
  System.out.println("数组a为空或者没有一个数据");
}
return result;

}
}

程序运行后,日志打印如下所示

从数组a中已经找到了4,它在第3个位置
未从数组a中找到11

3、插值查找算法

插值查找算法类似二分查找算法,它查找的数列必须是一个有序数列且存放是按照从小到大进行的。

我们用 start 表示数列起始位置的下标,用 end 表示数列终止位置的下标,findValue 表示要查找的数,用 arr 表示数组的名称,mid 表示 start 和 end 闭区间的一个数,它有可能是中间数,也有可能不是;对于插值查找算法,mid 的计算公式为:

int mid = start + (end - start) * (findValue - arr[start]) / (arr[end] - arr[start])

在已经排好序的序列中,先判断 arr[0] > findValue 又或者 findValue > arr[arr.length - 1] 这2个条件是否成立,如果不成立再计算 mid 并通过 findValue 与 mid 进行比较,如果相等,那么就证明已经找到,就退出循环;如果 findValue 比 arr[mid] 小,那么将 end = mid -1,也就是将 end 移动到 mid 左边一个位置,并且重新计算 mid;如果比 arr[mid] 大,那么将 start = mid + 1 ,也就是将 start 移动到 mid 右边一个位置,并且重新计算 mid;一直循环查找,直到 start > end,证明没找到对应的元素,停止循环。

我们举个例子再详细分析一下,假设我有一个数组 arr = {2, 12, 22, 32, 42, 52, 62, 72, 82, 92},一开始 start = 0,end = 9 。

3、1 假设查找 82

(1)arr[0] > findValue 又或者 findValue > arr[arr.length - 1] 这2个条件没有一个成立,那么计算 mid,mid=start + (end - start) (findValue - arr[start]) / (arr[end] - arr[start])= 0 + (9 - 0) (82 -2) / (92 - 2) = 8 。

(2)做比较,mid = 8,findValue = arr[8] = 82,正面2已经找到,退出循环。

3、2 假设查找 102

(1)findValue > arr[arr.length - 1] = arr[9] = 92,所以证明没有找到,结束查找 。

我们用代码实现一下:

public class Test8 {
public static void main(String[] args) {

int[] arr = { 2, 12, 22, 32, 42, 52, 62, 72, 82, 92 };
insertSearch(arr, 82);
insertSearch(arr, 102);

}

public static int insertSearch(int[] arr, int findValue) {

int result = -1;
if (arr != null && arr.length > 0) {
  if (findValue < arr[0] || findValue > arr[arr.length - 1]) {
    System.out.println("在arr数组中没有找到" + findValue);
  } else {
    int start = 0;
    int end = arr.length - 1;
    int mid = 0;
    int count = 0;
    while (true) {
      count++;
      System.out.println("第" + count + "次查找");
      mid = start + (end - start) * (findValue - arr[start])
          / (arr[end] - arr[start]);
      if (start > end) {
        System.out.println("在arr数组中没有找到" + findValue);
        break;
      } else if (findValue > arr[mid]) {
        start = mid + 1;
      } else if (findValue < arr[mid]) {
        end = mid - 1;
      } else {
        result = mid;
        System.out.println("在arr数组中已经找到了" + findValue + ",它在第"
            + mid + "个位置");
        break;
      }
    }
  }
} else {
  System.out.println("arr数组为空或者元素个数为0");
}
return result;

}
}

运行程序,日志打印如下所示:

第1次查找
在arr数组中已经找到了82,它在第8个位置
在arr数组中没有找到102

你可能感兴趣的:(java)