插值查找
1)插值查找原理介绍: 插值查找算法类似于二分查找,不同的是插值查找每次从自适应 mid 处开始查找。
2)将折半查找中的求 mid 索引的公式 :
(low 表示左边索引 left, high 表示右边索引 right;key 就是前面我们讲的findVal)
3)int mid = low + (high - low) * (key - arr[low]) / (arr[high] - arr[low]); /*插值索引*/
对应前面的代码公式:
int mid = left + (right – left) * (findVal – arr[left]) / (arr[right] – arr[left])
4)举例说明插值查找算法 1-100 的数组:
插值查找注意事项:
1) 对于数据量较大,关键字分布比较均匀的查找表来说,采用插值查找, 速度较快.。
2) 关键字分布不均匀的情况下,该方法不一定比折半查找要好。
代码实现
1. public class insertvaluesearch { 2. public static void main(String[] args) { 3. Integer[] arr = {45, 56, 22, 11, 123, 456, 898, 562, 121, 45, 20, 320, 112, 123};//无序数组 4. //注意:使用插值查找的前提也是 该数组是有序的. 5. 6. /*//降序排列方法: 7. Arrays.<Integer>sort(arr, new Comparator<Integer>() { 8. @Override 9. public int compare(Integer o1, Integer o2) { 10. return Integer.compare(o2, o1); 11. } 12. });*/ 13. Arrays.sort(arr);//升序排序 14. System.out.println("数组有序化后结果:" + Arrays.toString(arr)); 15. //arr = {11, 20, 22, 45, 45, 56, 112, 121, 123, 123, 320, 456, 562, 898}; 16. 17. int search = insertVauleSearch(arr, 0, arr.length - 1, 45); 18. List<Integer> searchAll = insertValueSearchAll(arr, 0, arr.length - 1, 45); 19. System.out.println(search); 20. System.out.println(searchAll); 21. } 22. 23. private static List<Integer> insertValueSearchAll(Integer[] arr, int left, int right, int findVal) { 24. if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) { 25. return null; 26. } else { 27. int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]); 28. if (findVal < arr[mid]) { 29. return insertValueSearchAll(arr, left, mid - 1, findVal); 30. } else if (findVal > arr[mid]) { 31. return insertValueSearchAll(arr, mid + 1, right, findVal); 32. } else { 33. ArrayList<Integer> list = new ArrayList<>(); 34. list.add(mid); 35. int t = mid - 1; 36. while (true) { 37. if (t < 0 || arr[t] != findVal) { 38. break; 39. } else { 40. list.add(t); 41. t--; 42. } 43. } 44. t = mid + 1; 45. while (true) { 46. if (t > arr.length - 1 || arr[t] != findVal) { 47. break; 48. } else { 49. list.add(t); 50. t++; 51. } 52. } 53. return list; 54. } 55. } 56. } 57. 58. private static int insertVauleSearch(Integer[] arr, int left, int right, int findVal) { 59. // 当 left > right 时,说明递归整个数组,但是没有找到 60. //注意:findVal < arr[0] 和 findVal > arr[arr.length - 1] 必须需要 61. //否则我们得到的 mid 可能越界(例如当findVal无穷大,则mid也为无穷大,则arr角标越界) 62. if (left > right || findVal < arr[0] || findVal > arr[arr.length - 1]) { 63. return -1; 64. } else { 65. // 求出 mid, 自适应 66. int mid = left + (right - left) * (findVal - arr[left]) / (arr[right] - arr[left]); 67. if (findVal < arr[mid]) {// 说明向左递归查找 68. return insertVauleSearch(arr, left, mid - 1, findVal); 69. } else if (findVal > arr[mid]) { // 说明应该向右边递归 70. return insertVauleSearch(arr, mid + 1, right, findVal); 71. } else { 72. return mid; 73. } 74. } 75. } 76. }