二分查询又被称为二分查找,是一种在有序数组或序列中快速查找到对应元素的一种方法。每次查找范围缩小至原来的一半。
数组和列表必须有序,否则无法进行二分查找。
确定查找数组和列表的左边界(通常为数组或列表第一个元素)和右边界(通常为数组和列表最后一个元素)。
如果查找到目标元素的索引,退出。
或者如果左边元素的索引大于右边元素,说明目标元素不在数组内,那么退出。
int BinaryFindValue(const int* arr, int n, int value)
{
int pos = -1;
if (n < 1 || arr == NULL) return pos;
int left = 0;
int right = n-1;
while (left<=right)
{
int mid = (right - left +1 ) / 2 + left;
if (value < arr[mid])
{
right = mid - 1;
}
else if (value > arr[mid])
{
left = mid + 1;
}
else
{
pos = mid;
break;
}
}
return pos;
}
int main()
{
const int n = 5;
int arr[n] = { 10,11,12,13,14 };
int val = 0;
scanf("%d", &val);
int m = BinaryFindValue(arr, n, val);
printf("%d", m);
}
也可以将这一行写成这样
int mid = (right - left +1 ) / 2 + left;
修改后:
int mid = (right - left + 1) >> 1 + left;
>>
是右移位操作符,在计算机中执行二进制位的右移。>> 1
表示将二进制位向右移动一位,相当于除以2。
注意这里有个问题:
int mid =((right - left + 1) >> 1) + left;
加号大于右移操作符,这样写的话是1+left然后右移,所以要给前面加上括号。
最终正确代码
int BinaryFindValue(const int* arr, int n, int value)
{
int pos = -1;
if (n < 1 || arr == NULL) return pos;
int left = 0;
int right = n-1;
while (left<=right)
{
int mid = ((right - left + 1) >> 1) + left;
if (value < arr[mid])
{
right = mid - 1;
}
else if (value > arr[mid])
{
left = mid + 1;
}
else
{
pos = mid;
break;
}
}
return pos;
}
int main()
{
const int n = 5;
int arr[n] = { 10,11,12,13,14 };
int val = 0;
scanf("%d", &val);
int m = BinaryFindValue(arr, n, val);
printf("%d", m);
}
Q:下面这个代码有问题,请详细说明原因
A:
问题一:是left 问题二:是使用(left+right)/2,如果left和right足够大,他们的mid很可能超出最大整数的范围,容易溢出。 修改: ① 修改判断条件,让left<=right的时候退出循环,这样就可以查找到边界的目标元素。 ②修改查找中间元素的计算方式,所以使用下面的方式只对区域进行取半。 如果我的序列中有多个重复的数字,我想要找到最左端数字的下标,你需要怎么做? 添加一个判断 判断arr[mid]和value相等的时候,它的前一个值是否也相等,但是这样写是错误的,因为如图,在下面的示例中,要找到12最左边元素的下标值,mid-1判断到mid=0下标的时候,再-1会造成越界,所以我们要对于判断条件增加。 增加一个条件mid-1>=0,防止越界行为,老师在这里增加的条件是mid>left,也是相同的道理,两种写法都可以。 在这里查找最左端元素的时候,你使用的是递归查询,请问怎么样使用二分法继续进行最左端元素的查找。 使用递归方法继续查找呢? 暂无思路,待补充…… 结构体是由我们自己设计的一种类型。 结构体和数组的区别:数组中所有元素的类型一致,但是结构体中元素的类型不需要一致。 结构体的定义 struct Student //结构体名 这里结束的时候记得写分号哦! 注意: 在C语言中,这里的Student是结构体名,struct Student是结构体类型名。在进行创建结构体变量时,需要使用结构体类型名创建。但是在C++中结构体类型名和结构体名没有区别。 Student sx;//错误 结构体的在声明的时候不需要初始化,因为它此时还是类型,不会开辟空间,所以不能赋初值。在定义结构体变量时,系统才会给结构体分配空间。 初始化顺序需要与结构体声明次序保持一致。 结构体嵌套结构体初始化,也是使用花括号初始化。 或者写成这个样子也是可以的: 如果结构体内的数组是按照[ ]方式声明的,定义变量的时候,栈区为数组分配对应字节的空间。4.优化一
while (arr[mid - 1] == value)
{
mid--;
}
pos = mid;
break;
//while ((mid>left) && (arr[mid - 1] == value))
while ((mid-1 >= 0) && (arr[mid - 1] == value))
{
mid--;
}
pos = mid;
break;
int BinaryFindValue(const int* arr, int n, int value)
{
int pos = -1;
if (n < 1 || arr == NULL) return pos;
int left = 0;
int right = n-1;
while (left<=right)
{
int mid =((right - left + 1) >> 1) + left;
if (value < arr[mid])
{
right = mid - 1;
}
else if (value > arr[mid])
{
left = mid + 1;
}
else
{
while ((mid-1 >= 0) && (arr[mid - 1] == value))
{
mid--;
}
pos = mid;
break;
}
}
return pos;
}
int main()
{
const int n = 13;
int arr[n] = { 12,12,12,13,13,13,13,13,24,24,24,25,26};
int val = 0;
scanf("%d", &val);
int m = BinaryFindValue(arr, n, val);
printf("%d", m);
}
5.优化二
二、结构体
1.定义
{
//成员列表
};
struct Student sx;//正确 2.初始化
①使用花括号初始化
struct Student
{
char s_name[20];
int age;
};
int main()
{
struct Student sx = { "lizeyu",23 };
printf("%s %d\n", sx.s_name, sx.age);
}
struct Date
{
int year;
int month;
int day;
};
struct Student
{
char s_name[20];
Date birthday;
int age;
};
int main()
{
struct Student sx = { "lizeyu",{2000,8,21},23 };
printf("%s %d\n", sx.s_name, sx.age);
}
struct Student sx = { "lizeyu",2000,8,21,23 };
3.结构体在内存中的存储