目录
一、线性查找
二、二分查找
基础版
问题1 —— 循环条件
问题2 —— i+j/2有没有问题
问题3 —— 代码中都写成 < 有何好处
改动版
人生的意义就是要独自穿过悲喜
—— 24.8.27
需求:在有序数组A内,查找值 target,如果找到返回索引,如果找不到返回 -1
一、线性查找
待查找的数组,可以不是有序数组
// 线性查找法
public static int StrFind(int target,int[] arr){
for(int i=0;i<arr.length;i++){
if(arr[i]==target){
return i;
}
}
return -1;
}
二、二分查找
待查找的数组必须是升序数组
1.基础版
问题1 —— 循环条件
为什么在写while循环时,条件为i<=j而不是i<j
因为会省略i=j时的元素
问题2 —— (i+j) / 2有没有问题
为避免(两个大数相加,将第一位当作符号位,最终得出负数)数值过大,大于整数最大值后,除2得不到正确的答案,所以改为无符号右移,也可以适用于更多的语言
问题3 —— 代码中都写成 < 有何好处
因为数组中是升序排列,比较别扭,其他同理
// 二分查找基础版
public static int BS(int target,int[] arr){
int i = 0, j = arr.length-1;
while(i <= j){
// 为避免(两个大数相加,将第一位当作符号位,最终得出负数)数值过大,大于整数最大值后,除2得不到正确的答案,所以改为无符号右移,也可以适用于更多的语言
// int mid = (i+j)/2;
int mid = (i+j) >>> 1;
if(arr[mid]==target){
return mid;
}else if(arr[mid]<target){
i = mid+1;
}else {
j = mid-1;
}
}
return -1;
}
public class demo1BinarySearch {
// 线性查找法
public static int StrFind(int target,int[] arr){
for(int i=0;i<arr.length;i++){
if(arr[i]==target){
return i;
}
}
return -1;
}
// 二分查找基础版
public static int BS(int target,int[] arr){
int i = 0, j = arr.length-1;
while(i <= j){
// 为避免(两个大数相加,将第一位当作符号位,最终得出负数)数值过大,大于整数最大值后,除2得不到正确的答案,所以改为无符号右移,也可以适用于更多的语言
// int mid = (i+j)/2;
int mid = (i+j) >>> 1;
if(arr[mid]==target){
return mid;
}else if(arr[mid]<target){
i = mid+1; // 目标值在右边
}else {
j = mid-1; // 目标值在左边
}
}
return -1;
}
public static void main(String[] args) {
int[] arr = {7,12,19,27,35,42,43,44};
int target1 = 30;
int target2 = 43;
int res1 = StrFind(target1,arr);
System.out.println("res1 = "+res1);
int res2 = BS(target2,arr);
System.out.println("res2 = "+res2);
int res3 = BS(19,arr);
System.out.println("res3 = "+res3);
}
}
2.改动版
为避免当数组中存在趋于中间位置,却又不存在的查找数,进行的三处改动
// 二分查找改动版
public static int binarySearch2(int[] arr, int target) {
int i = 0, j = arr.length; // 第一处改动
while (i < j) { // 第二处改动
int mid = (i+j) >>> 1;
if (arr[mid] == target) {
return mid;
}else if(arr[mid] < target) {
i = mid + 1;
}else {
j = mid; // 第三处改动
}
}
return -1;
}
3.平衡版
① 左闭右开的区间,i指向的可能是目标,而ì指向的不是目标
② 不在循环内找出,等范围内只剩ì时,退出循环,在循环外比较 a[i] 与 target
③ 循环内的平均比较次数减少了
④ 时间复杂度 O(log(n))
// 二分查找平衡版
public static int binarySearch3(int[] arr, int target) {
int i = 0, j = arr.length;
while (1 < j - i) {
int mid = (i + j) >>> 1;
if (target < arr[mid]) {
j = mid;
}else{
i = mid;
}
}
if (arr[i] == target) {
return i;
}else{
return -1;
}
}
package Day1;
public class demo1BinarySearch {
// 线性查找法
public static int StrFind(int target,int[] arr){
for(int i=0;i<arr.length;i++){
if(arr[i]==target){
return i;
}
}
return -1;
}
// 二分查找基础版
public static int BS(int target,int[] arr){
int i = 0, j = arr.length-1;
while(i <= j){
// 为避免(两个大数相加,将第一位当作符号位,最终得出负数)数值过大,大于整数最大值后,除2得不到正确的答案,所以改为无符号右移,也可以适用于更多的语言
// int mid = (i+j)/2;
int mid = (i+j) >>> 1;
if(arr[mid]==target){
return mid;
}else if(arr[mid]<target){
i = mid+1; // 目标值在右边
}else {
j = mid-1; // 目标值在左边
}
}
return -1;
}
// 二分查找改动版
public static int binarySearch2(int[] arr, int target) {
int i = 0, j = arr.length; // 第一处改动
while (i < j) { // 第二处改动
int mid = (i+j) >>> 1;
if (arr[mid] == target) {
return mid;
}else if(arr[mid] < target) {
i = mid + 1;
}else {
j = mid; // 第三处改动
}
}
return -1;
}
// 二分查找平衡版
public static int binarySearch3(int[] arr, int target) {
int i = 0, j = arr.length;
while (1 < j - i) {
int mid = (i + j) >>> 1;
if (target < arr[mid]) {
j = mid;
}else{
i = mid;
}
}
if (arr[i] == target) {
return i;
}else{
return -1;
}
}
public static void main(String[] args) {
int[] arr = {7,12,19,27,35,42,43,44};
int target1 = 30;
int target2 = 43;
int res1 = StrFind(target1,arr);
System.out.println("res1 = "+res1);
int res2 = BS(target2,arr);
System.out.println("res2 = "+res2);
int res3 = BS(19,arr);
System.out.println("res3 = "+res3);
int res4 = binarySearch2(arr,27);
System.out.println("res4 = "+res4);
int res5 = binarySearch3(arr,35);
System.out.println("res5 = "+res5);
}
}