徹底輕鬆搞定順序儲存結構元素的二分查詢的時間複雜度優勢以及如何算時間複雜度
二分查詢也叫折半查詢,根據字面意思大概知道是怎麼個查詢具體一個元素的吧。
首先分析下查詢過程:
我們先通過被查詢的陣列得到該被查詢陣列的第一個索引和最後一個索引值,假如我們拿陣列10個元素來做例子
我們得到索引0和索引9 mid = (min(0) + max(9))/2 mid =5 得到中間索引然後就測試當前這個索引對應的元素是不是我們想要的元素,是的話就直接返回元素的索引下標,
否則我們根據和當前元素的大小,確實我們被查詢元素在什麼區間。
現在引出了為什麼二分查詢的物件必須是有序的,
既然規定是有序的,假如我們查詢的元素大於當前的中間值,我們預設資料是從小到大,
那麼我們的查詢對應肯定是在索引值為6和9之間,你們說是不是。因此我們把查詢範圍直接鎖定在6和9之間,還是用同樣的辦法繼續將迴圈範圍減半。 最好只有一個元素的時候比較之後就不用在折半陣列了,直接退出迴圈。
貼上演算法:
//折半演算法實現程式碼 c++版本 其實語言沒有關係
//使用者想用我這個演算法查詢一個元素在陣列array中的索引位置
//直接告訴我們陣列的起點索引和終點索引 以及查詢的對於key
void BinSearch(int array[] ,int low, int high,int key)
{
//既然用了遞迴,那麼什麼時候退出呢
//當我們的資料只有一個了我們直接比較就可以 比較後發現不等就直接退出了反正找不到了
if(low >= high)
{
return -1; //-1表示沒有找到
}
//開始為比較元素大小準備中間變數 得到被查詢陣列的中間元素索引值
int mid = (low + high)/2;
//開始比較元素是不是想要的
if(array[mid] == key)//找到了
{
return mid; //直接把查詢到的key值返回給用![這裡寫圖片描述](https://img-blog.csdn.net/20171116132618667?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcXFfMzMwNjA0MDU=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)戶
}
else if(arrat[mid] > key) //發現查詢物件是在我們的陣列中間索引的左邊
{
//縮小了查詢的範圍,還是相同問題,因此可以用遞迴演算法查詢
//我需要把被查詢陣列和陣列的下標以及被查詢的資料傳給當前函式
return BinSearch(array,low, mid-1, key);
}else //說明查詢物件在mid的右邊 那麼把對應需要的索引範維傳過去
{
return BinSearch(array,mid + 1, high, key);
}
}
下面進入我們的主題:
先看圖
圖理可不是二叉樹哦。我們拿來用,我們的資料還是用順序表儲存,總共11個元素,
並且儲存次順依次是 2 3 10 15 20 25 28 29 30 35 40,大家發現沒有我們用中序遍歷這個二叉樹圖就是這個序列。
好了 我們的陣列是存的上序序列,假如我查詢40這個數, 進入我們的演算法查詢過程我們先是和mid = 5 就是25比較大小,比較一次。
然後沒有找到的話就假如當前的查詢資料大於25,那麼我們就轉到30根節點那邊的樹,和30比較又 是1次,
接著轉35那棵樹和35比較是1次,然後就是40又是一次找到了。 總共是4次比較,
大家細細數數二叉樹的高度也是4啊,那麼查詢次數是不是就是所要的元素在二叉樹的高度呢。
回答是對的, 比如我們想找30的話,我們只要比較2次就可以。那麼我們的平均查詢次數是怎麼算呢。
答案是把每個元素查詢的次是求和處以全部節點數: ASL = (1 + 2*2+ 3*4 + 4*4)/11;
那麼ASL 什麼呢 是平均查詢長度 為啥 看這裡:Average Search Length 好了吧,哈哈
那麼1 2 3 4 又是什麼呢,1表示我們查詢25這個元素需要一次 ,2 是2次剛好有10和30個元素所以就是4次。 其他一樣。如果是n個元素,那麼這個平均查詢次數就是關於n的函式,就可以演算法時間複雜度了
我們知道二叉樹的高度和節點在數學上的關係,假如有n個節點,樹的高度為h,那麼h = log2^(n + 1);
具體是為什麼我們可以代數測試。為了簡單起見,當樹的高度為1, 那麼節點n+ 1 = 2 ,從而n = 1.滿足二叉樹
當樹高度為2 , n + 1 = 4 即 n = 3,
當我們的陣列元素是n個的時候,我們在來求二分法找元素的ASL的大小,不好寫就直接上圖了
具體算時間複雜度的公式直接給出把。就是0(log2^n) 他就是數學裡面的一個曲線圖,根據這個圖我們知道查詢效率根據這個n的變化的趨勢; 這個根據平均長度很多容易得出,為什麼去掉 + 1 和- 1,我估計說下,我那線性表按照次順查詢來說,簡單點,假如平均查詢次數是2n + 1, 那麼時間複雜度是0(n),
為什麼,我們需要把這個2n + 1直線畫出來,我們可以看到n變化帶來y的變化趨勢, 因此其實時間複雜度是看圖的走勢,也就是說隨著資料n的無限增大,需要的查詢次數是不是增加很快。如果說變得非常快你的演算法需要改進了,如果變得很小,甚至就是個常量,那麼恭喜你牛B的演算法出了,不用優化了,至少目前很多年是不會。0(n) 和0(log2^n)的走勢圖 肯定後面直線的一定會在上面也就是說次數會一直高,越到後面拉的差距也越大。
大家發現了嗎,同樣都是陣列來存資料,我們在陣列中找個元素,我們用迴圈依次比較法和二分法區別就很大了。特別在海量資料中查詢更加明顯。商業專案中的資料你覺得那幾個嗎,肯定是千萬級別。
所以你知道演算法為啥在公司必考麼。 寫出那麼弱的演算法的很多演算法在專案中根本不能用的,使用者體驗是接受不了。所以跟著我把資料結構和演算法徹底搞定在進軍其他的技術把。
曲線圖就不貼了 大家有精力可以看看數學視訊或者自己畫出來。
其實計算時間複雜度其他的就類似了,知道了方法靠的是什麼就是死啃了 ,沒有捷徑, 這個時候對於覺得數學到底對遊戲開發有什麼好處啊,要不要學啊。就很明顯了,畫圖 log等函式這些其實都是數學中的知識,高中學過吧,不記得的話可以複習下哦。遇到不懂得一一搞定,後面不懂得越來越來少,一直在託不懂得還是不懂。、