顺序表查找 顺序查找 顺序查找(Sequential Search) :从第一个到最后一个记录依次与给定值比较,若相等则查找成功。
顺序查找优化 :设置哨兵,可以避免每次循环都判断是否越界。在数据量很多时能提高效率。
时间复杂度 :O(n),n为记录的数。
代码实现 1 2 3 4 5 6 7 8 public static int seqSearch (int [] array, int key) { int length = array.length; for (int i = 0 ; i < length; i++) { if (key == array[i]) return i; } return -1 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 public static int seqSearch2 (int [] array, int key) { int index = array.length - 1 ; if (key == array[index]) { return index; } array[index] = key; int i = 0 ; while (array[i++] != key) ; return i == index + 1 ? -1 : i - 1 ; }
有序表查找 折半查找(二分查找) 必须满足两个前提:
存储结构必须是顺序存储
关键码必须有序排列
假设数据按升序排列。从中间项与关键值(key)开始对比,若关键值(key)>中间值,则在右半区间继续查找,反之则左半区间继续查找。以此类推,直至找到匹配值,或者查找内无记录,查找失败。
代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static int binarySearch (int [] array, int key) { int low = 1 ; int high = array.length - 1 ; while (low <= high) { int mid = (low + high) / 2 ; if (array[mid] < key) low = mid + 1 ; else if (array[mid] > key) high = mid - 1 ; else return mid; } return 0 ; }
递归实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static int binarySearch2 (int [] array, int value) { int low = 0 ; int high = array.length - 1 ; return search(array, low, high, value); } private static int search (int [] array, int low, int high, int value) { if (low > high) { return -1 ; } int mid = low + ((high - low) >> 1 ); if (value == array[mid]) { return mid; } if (value < array[mid]) { return search(array, low, mid - 1 , value); } return search(array, mid + 1 , high, value); }
插值查找 对于表长较大,关键字分布比较均匀的查找表来说,可以采用插值查找:
将折半查找mid的过程:
改为:
代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 public static int insertSearch (int [] array, int key) { int low = 1 ; int high = array.length - 1 ; while (low <= high) { int mid = low + (high - low) * (key - array[low]) / (array[high] - array[low]); if (array[mid] < key) low = mid + 1 ; else if (array[mid] > key) high = mid - 1 ; else return mid; } return 0 ; }
递归实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public static int insertSearch2 (int [] array, int key) { return search2(array, key, 0 , array.length - 1 ); } private static int search2 (int [] array, int key, int left, int right) { if (left > right) return -1 ; if (array[right] == array[left]) { if (array[right] == key) return right; else return -1 ; } int mid = left + (key - array[left]) / (array[right] - array[left]) * (right - left); if (array[mid] == key) return mid; if (array[mid] > key) return search2(array, key, left, mid - 1 ); return search2(array, key, mid + 1 , right); }
斐波那契查找 斐波那契数列如下:
斐波那契查找 原理与前两种相似,仅仅改变了中间结点(mid)的位置,mid不再是中间或插值得到,而是位于黄金分割点附近,即mid=low+F(k-1)-1 (F代表斐波那契数列),如下图所示:
对F(k-1)-1的理解:
由斐波那契数列 F[k]=F[k-1]+F[k-2] 的性质,可以得到 (F[k]-1)=(F[k-1]-1)+(F[k-2]-1)+1 。该式说明:只要顺序表的长度为F[k]-1 ,则可以将该表分成长度为F[k-1]-1 和F[k-2]-1 的两段,即如上图所示。从而中间位置为mid=low+F(k-1)-1 。
类似的,每一子段也可以用相同的方式分割,从而方便编程。
但顺序表长度n不一定刚好等于F[k]-1,所以需要将原来的顺序表长度n增加至F[k]-1。这里的k值只要能使得F[k]-1恰好大于或等于n即可,由以下代码得到:
顺序表长度增加后,新增的位置(从n+1到F[k]-1位置),都赋为n位置的值即可。
代码实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public static int fib (int n) { if (n == 0 ) return 0 ; if (n == 1 ) return 1 ; return fib(n - 1 ) + fib(n - 2 ); } public static int fib2 (int n) { int a = 0 ; int b = 1 ; if (n == 0 ) return a; if (n == 1 ) return b; int c = 0 ; for (int i = 2 ; i <= n; i++) { c = a + b; a = b; b = c; } return c; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public static int fibSearch (int [] array, int key) { if (array == null || array.length == 0 ) return -1 ; int length = array.length; int k = 0 ; while (length > fib(k) - 1 || fib(k) - 1 < 5 ) { k++; } int [] fb = makeFbArray(fib(k) - 1 ); int [] temp = Arrays.copyOf(array, fb[k] - 1 ); for (int i = length; i < temp.length; i++) { temp[i] = array[length - 1 ]; } int low = 0 ; int hight = length - 1 ; while (low <= hight) { int middle = low + fb[k - 1 ] - 1 ; if (temp[middle] > key) { hight = middle - 1 ; k = k - 1 ; } else if (temp[middle] < key) { low = middle + 1 ; k = k - 2 ; } else { if (middle <= hight) { return middle; } else { return hight; } } } return -1 ; } private static int fib (int n) { if (n == 0 || n == 1 ) return n; return fib3(n - 1 ) + fib3(n - 2 ); } public static int [] makeFbArray(int length) { int [] array = new int [length]; array[0 ] = 0 ; array[1 ] = 1 ; for (int i = 2 ; i < length; i++) array[i] = array[i - 1 ] + array[i - 2 ]; return array; }