二分查找以及变异

来源:互联网 发布:java开发合同管理系统 编辑:程序博客网 时间:2024/04/29 10:24

二分查找
1 必须是数组结构,实现查找o(1)。如果是用链表存储的,就无法在其上应用二分查找法了。
2 排序排序
时间复杂度:log(n)

二分查找的基本算法:
递归
array为排序数组
int binarysearch (int array[], int low, int high, int target)
{
if (low > high) return -1;

int mid =low+(high-low)/2;if (array[mid]> target)    return    binarysearch(array, low, mid -1, target);if (array[mid]< target)    return    binarysearch(array, mid+1, high, target);//if (midValue == target)    return mid;

}
循环:
int binarysearch (int array[], int low, int high, int target)
{
while(low <= high)
{
int mid = (low + high)/2;
if (array[mid] > target)
high = mid - 1;
else if (array[mid] < target)
low = mid + 1;
else //find the target
return mid;
}
//the array does not contain the target
return -1;
}

二分查找法的缺陷
二分查找法的O(log n)让它成为十分高效的算法。不过它的缺陷却也是那么明显的。就在它的限定之上:必须有序,我们很难保证我们的数组都是有序的。当然可以在构建数组的时候进行排序,可是又落到了第二个瓶颈上:它必须是数组。数组读取效率是O(1),可是它的插入和删除某个元素的效率却是O(n)。因而导致构建有序数组变成低效的事情。
解决这些缺陷问题更好的方法应该是使用二叉查找树了,最好自然是自平衡二叉查找树了,自能高效的(O(nlogn))构建有序元素集合,又能如同二分查找法一样快速(O(log n))的搜寻目标数。插入、删除和查找算法的时间复杂度均为O(lgn)。

    二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有 下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。   AVL平衡二叉树或为空树,或为如下性质的二叉排序树:  (1)左右子树深度之差的绝对值不超过1;  (2)左右子树仍然为平衡二叉树.   平衡因子BF=左子树深度-右子树深度.各项操作的时间复杂度:它的插入和删除某个元素的效率O(logN)

2.1.3 Search in Rotated Sorted Array
描述
Suppose a sorted array is rotated at some pivot unknown to you beforehand.
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
You are given a target value to search. If found in the array return its index, otherwise return -1.
You may assume no duplicate exists in the array.

2.1.4 Search in Rotated Sorted Array II
描述
Follow up for ”Search in Rotated Sorted Array”: What if duplicates are allowed?
Would this affect the run-time complexity? How and why?
Write a function to determine if a given target is in the array.
//判读一个taregt是否存在有序数组中

考察二分法
**/*分析:
123456789—》6789 1 2345
arr[begin]>arr[mid]
应该是6789 1 2345 后面肯定是升序 然后根据target目标来决定前面还是后面
arr[begin]<arr[mid]
应该是 3456 7 8912 前面肯定是升序 然后根据target目标来决定前面还是后

 */****
function f7(&$arr,$target,$begin,$end){    if(false===is_array($arr)||empty($arr)) return -1;    if($end<$begin) return -1;    $mid=$begin+intval(($end-$begin)/2);    if($arr[$mid]==$target){        return $mid;    }    /*这是写错的    if($arr[$mid]>$target){         if($arr[$begin]>$target){              return f($arr,$target,$mid+1,$end);         }else{               return f($arr,$target,$begin,$mid-1);        }    }else{         if($arr[$end]>$target){            return f($arr,$target,$mid+1,$end);            }else{            return f($arr,$target,$begin,$mid-1);            }    }*/    if($arr[$begin]>$arr[$mid]){        if($target>$arr[$mid]&&$target<$arr[$end]){            return f7($arr,$target,$mid+1,$end);        }else{            return f7($arr,$target,$begin,$mid-1);        }    }else if($arr[$begin]<$arr[$mid]){        if($target<$arr[$mid]&&$target>$arr[$begin]){            return f7($arr,$target,$begin,$mid-1);        }else{            return f7($arr,$target,$mid+1,$end);        }    }else{//出现相同的时候        return f7($arr,$target,$begin+1,$end);    }}

这里写图片描述

这个写错了*function findSmall($arr,$begin,$end){    if(false===is_array($arr))  return false;    if($end<$begin) return ;    $n=$end-$begin;    if($n==0) return $arr[$begin];    if($n==1) return min($arr[$begin],$arr[$end]);    $mid=$begin+intval(($end-$begin)/2);    if($arr[$mid]>$arr[$begin]){        if($arr[$mid]>$arr[$end])            return findSmall($arr,$mid+1,$end);        else            return findSmall($arr,$begin,$mid-1);    }else{            return findSmall($arr,$mid,$end);错了    }}

这种题,重点在于根据题意,缩小寻找的范围;
旋转数组的特点:根据判断中间mid和开头对应值的大小来判断前(后)段是升序。
123456789—》6789 1 2345
arr[begin]<arr[mid]
应该是5678 9 1234 前面肯定是升序 ,最小的的肯定在后面。
但是要注意特例:
1234 5 6789 这时候最小的在前面尼。。。
反之 后面肯定是升序,但是最小在前面
例如7891 2 3456 最小在前面

 function findSmall($arr,$begin,$end){    if (false === is_array($arr)) return false;    if ($end < $begin) return;    $n = $end - $begin;    if ($n == 0) return $arr[$begin];    if ($n == 1) return min($arr[$begin], $arr[$end]);    $mid = $begin + intval(($end - $begin) / 2);    /*    该题还要考虑是否存在相同的值    例如    11 1 01    这种情况只能采用顺序查找了。     */    if ($arr[$mid] == $arr[$begin] && $arr[$mid] == $arr[$end])        return shunFind($arr,$begin,$end);    if ($arr[$mid] > $arr[$begin]){        if ($arr[$mid] < $arr[$end]){            return findSmall($arr, $begin, $mid);        }else            return findSmall($arr, $mid, $end);     }else       return findSmall($arr,$begin,$mid);}     

2 .1.5 Median of Two Sorted Arrays
描述
There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. the overall run time complexity should be O(log(m + n)).

这个题下标要想清楚~,很容易出错
0 0
原创粉丝点击