折半查找
又称为二分查找。这种查找方法要求查找表的数据是线性结构保存,并且还要求查找表中的数据是按关键字由小到大有序排列。
折半查找(二分查找)是一种简单而又高效的查找算法,其查找长度至多为㏒2n+1(判定树的深度),平均查找长度为㏒2(n+1)-1,效率比顺序查找要高,但折半查找只能适用于顺序存储有序表(如对线性链表就无法有效地进行折半查找)。
经典非递归算法实现
int Binary_Search(int search_table[], int key, int low ,int high)
{
while(low <= high)
{
mid = (low + high) / 2;
if(search_table[mid] < key)
{
low = mid + 1;
}
else if(search_table[mid] > key)
{
high = mid - 1;
}
else
{
return mid;
}
}//while
return -1;
}
经典递归算法实现
int Binary_Search(int search_table[], int key, int low ,int high)
{
if(low > high)
{
return -1;
}
int mid = (low + high) / 2;
if(search_table[mid] == key)
{
return mid;
}
else if(search_table[mid] < key)
{
Binary_Search(search_table, key, mid + 1, high);
}
else
{
Binary_Search(search_table, key, low, mid - 1);
}
}
不过,由于折半查找的前提条件是需要有序表顺序存储,对于静态查找表,一次排序后不再变化,这样的算法已经比较好了。但是对于频繁执行插入或删除操作的数据集来说,维护有序的排序会带来不小的工作量,那就不建议使用了。
说一个小的知识点:
mid = (first + last) / 2;
//等价于
mid = first + (last - first) / 2;
如果把一个有序的线性数组放到一个二维数组中,那么同样可以利用二分查找:
在这个数组上面查找
bool searchMatrix(vector<vector<int>>& matrix, int target)
{
bool found = false;
int m = matrix.size();//行数
int n = matrix[0].size();//列数
int first = 0;
int last = m * n - 1;
while(first <= last)
{
int mid = (first + last) / 2;
if(matrix[mid / n][mid % n] == target)
{
found = true;
break;
}
else if(matrix[mid / n][mid % n] > target)
{
last = mid - 1;
}
else
{
first = mid + 1;
}
}//while
return found;
}
折半查找扩展
折半查找的思想其实就是,每次查找之后,能缩小下次查找的范围,这一点很重要。以后所有的查找问题,只要是在有序的线性表上查找或者半有序的线性表上查找,都要往折半查找上靠拢,想着每次查找之后,能缩小下次查找的范围。
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。
请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
只要遇到了有序的查找,就往折半查找上想办法,同时想着怎么能缩小下次查找的范围。
bool searchMatrix(vector<vector<int>>& matrix, int target)
{
int row = matrix.size();
int column = matrix[0].size();
bool found = false;
int i = 0;
int j = column - 1;
while(i < row && j >= 0)
{
if(matrix[i][j] > target)
{
--j;
}
else if(matrix[i][j] < target)
{
++i;
}
else
{
found = true;
break;
}
}//while
return found;
}
这里存储二维数组用的是vector,当然也可以用一个int类型的指针,然后通过行数和列数访问二维数组每一个元素。