【44期】盤點那些必問的數(shù)據(jù)結構算法題之二分查找算法
0 概述
1 二分查找基礎
/**
?*?基本二分查找算法
?*/
int?binarySearch(int?a[],?int?n,?int?t)
{
????int?l?=?0,?u?=?n?-?1;
????while?(l?<=?u)?{
????????int?m?=?l?+?(u?-?l)?/?2;?//?同(l+u)/?2,這里是為了防溢出
????????if?(t?>?a[m])
????????????l?=?m?+?1;
????????else?if?(t?????????????u?=?m?-?1;
????????else
????????????return?m;
????}
????return?-(l+1);
}
http://blog.csdn.net/ssjhust123/article/details/7798737
2 查找有序數(shù)組中數(shù)字第一次出現(xiàn)位置
/**
?*?二分查找第一次出現(xiàn)位置
?*/
int?binarySearchFirst(int?a[],?int?n,?int?t)
{
????int?l?=?-1,?u?=?n;
????while?(l?+?1?!=?u)?{
????????/*循環(huán)不變式a[l]
????????int?m?=?l?+?(u?-?l)?/?2;?//同(l+u)/?2
????????if?(t?>?a[m])
????????????l?=?m;
????????else
????????????u?=?m;
????}
????/*assert:?l+1=u?&&?a[l]
????int?p?=?u;
????if?(p>=n?||?a[p]!=t)
????????p?=?-1;
????return?p;
}
a[-1] < t <= a[n],但是我們并不會去訪問這兩個元素,因為(l+u)/2 > l=-1,?(l+u)/2 < u=n。循環(huán)不變式為la[l] && t<=a[u]?。循環(huán)退出時必然有l(wèi)+1=u, 而且a[l] < t <= a[u]。舉個例子:對于數(shù)組a={1, 2, 3, 3, 5, 7, 8},我們如果查找t=3,則可以得到p=u=2,如果查找t=4,a[3] =n, 比如t=9,則u=7,此時也是設置p=-1.特別注意的是,l=-1,u=n這兩個值不能寫成l=0,u=n-1。雖然這兩個值不會訪問到,但是如果改成后面的那樣,就會導致二分查找失敗,那樣就訪問不到第一個數(shù)字。如在a={1,2,3,4,5}中查找1,如果初始設置l=0,u=n-1,則會導致查找失敗。
擴展
/**
?*?二分查找最后一次出現(xiàn)位置
?*/
int?binarySearchLast(int?a[],?int?n,?int?t)
{
????int?l?=?-1,?u?=?n;
????while?(l?+?1?!=?u)?{
????????/*循環(huán)不變式,?a[l]?<=?t?
????????int?m?=?l?+?(u?-?l)?/?2;
????????if?(t?>=?a[m])
????????????l?=?m;
????????else
????????????u?=?m;
????}
????/*assert:?l+1?=?u?&&?a[l]?<=?t?
????int?p?=?l;
????if?(p<=-1?||?a[p]!=t)
????????p?=?-1;
????return?p;
}
/**
?*?二分查找第一次和最后一次出現(xiàn)位置
?*/
int?binarySearchFirstAndLast(int?a[],?int?n,?int?t,?int?firstFlag)
{
????int?l?=?0;
????int?u?=?n?-?1;
????while(l?<=?u)?{
????????int?m?=?l?+?(u?-?l)?/?2;
????????if(a[m]?==?t)?{?//找到了,判斷是第一次出現(xiàn)還是最后一次出現(xiàn)
????????????if(firstFlag)?{?//查詢第一次出現(xiàn)的位置
????????????????if(m?!=?0?&&?a[m-1]?!=?t)
????????????????????return?m;
????????????????else?if(m?==?0)
????????????????????return?0;
????????????????else
????????????????????u?=?m?-?1;
????????????}?else?{???//查詢最后一次出現(xiàn)的位置
????????????????if(m?!=?n-1?&&?a[m+1]?!=?t)
????????????????????return?m;
????????????????else?if(m?==?n-1)
????????????????????return?n-1;
????????????????else
????????????????????l?=?m?+?1;
????????????}
????????}
????????else?if(a[m]?????????????l?=?m?+?1;
????????else
????????????u?=?m?-?1;
????}
????return?-1;
}
3 旋轉數(shù)組元素查找問題
題目
分析
/**
?*?旋轉數(shù)組查找-兩次二分查找
?*/
int?binarySearchRotateTwice(int?a[],?int?n,?int?t)
{
????int?p?=?findRotatePosition(a,?n);?//找到旋轉位置
????if?(p?==?-1)
????????return?binarySearchFirst(a,?n,?t);?//如果原數(shù)組有序,則直接二分查找即可
????int?left?=?binarySearchFirst(a,?p+1,?t);?//查找左半部分
????if?(left?!=?-1)
????????return?left;?//左半部分找到,則直接返回
????int?right?=?binarySearchFirst(a+p+1,?n-p-1,?t);?//左半部分沒有找到,則查找右半部分
????if?(right?==?-1)
????????return?-1;
????return?right+p+1;??//返回位置,注意要加上p+1
}
/**
?*?查找旋轉位置
?*/
int?findRotatePosition(int?a[],?int?n)
{
????int?i;
????for?(i?=?0;?i?-1;?i++)?{
????????if?(a[i+1]?????????????return?i;
????}
????return?-1;
}
如果左邊是有序的,若?
ta[l], 則 u=m-1;其他情況,l =m+1;如果右邊是有序的,若?
t> a[m] && t?則 l=m+1;其他情況,u =m-1;
/**
?*?旋轉數(shù)組二分查找-一次二分查找
?*/
int?binarySearchRotateOnce(int?a[],?int?n,?int?t)
{
????int?l?=?0,?u?=?n-1;
????while?(l?<=?u)?{
????????int?m?=?l?+?(u-l)?/?2;
????????if?(t?==?a[m])
????????????return?m;
????????if?(a[m]?>=?a[l])?{?//數(shù)組左半有序
????????????if?(t?>=?a[l]?&&?t?????????????????u?=?m?-?1;
????????????else
????????????????l?=?m?+?1;
????????}?else?{???????//數(shù)組右半段有序
????????????if?(t?>?a[m]?&&?t?<=?a[u])
????????????????l?=?m?+?1;
????????????else
????????????????u?=?m?-?1;
????????}???
????}???
????return?-1;?
}
推薦閱讀:
【43期】盤點那些必問的數(shù)據(jù)結構算法題之二叉樹基礎
【42期】盤點那些必問的數(shù)據(jù)結構算法題之二叉堆
【41期】盤點那些必問的數(shù)據(jù)結構算法題之鏈表
微信掃描二維碼,關注我的公眾號
朕已閱?
評論
圖片
表情

