歡迎來到查找的世界,在學習完各類數據結構以後,總算走到了這一步,不知道你們有什麼感想呢?反正我是邊學邊忘,如今讓我去說說圖的那幾個算法仍是在蒙圈的狀態中。不過學習嘛,就是一步一步的來,暫時搞不懂的東西其實也是能夠放一放的。打破砂鍋和堅持不懈固然是好的品德,但有些東西可能真的是須要時間去消化的,甚至多是須要真實的項目經歷才能完全搞明白。在咱們編程行業來講就是典型的這種實踐的學習形式效果會更好,不少人在上大學的時候對於數據結構以及其它專業課都是以死記硬背爲主,包括上了多少年班的同窗可能都沒有在業務代碼中真正的使用過什麼算法,因此理解它們確實是很是困難的。這時,咱們能夠暫時休息一下,轉換一下思路,學習最主要的就是預習和複習,在此次學習完以後,未來再進行屢次的複習,研究各類不一樣的資料,早晚有一天你們都能搞明白的。php
今天的內容其實就很是簡單了,能夠說是除了線性表以外最簡單的內容。咱們只研究兩個很是初級的查找,那就是順序查找和折半查找。相信很多同窗可能早就會了,通常培訓機構講數據結構和算法時,查找必講二分,排序必講冒泡,更不用說正規大學對口專業出身的同窗了。固然,這兩個也是很是簡單的,無論你有沒有基礎,我們一塊兒來看看吧。git
無論你是什麼算法題,仍是在實際的業務開發中,查找都是很是重要的,甚至可能比排序還要重要。想一想你成天面向數據庫編程是在幹嗎?不就是 CRUD 嘛,其中大部的業務還都是以搜索查找居多,咱們在優化數據庫時,也主要是優化各類查詢語句。固然,要說到數據庫的查找那就過高深了,之後咱們學習 MySQL 相關的知識時再詳細講解,特別是索引中的 B+ 樹,就是數據結構和算法的核心思想的體現。好吧,不吹牛了,也不敢在這裏多說了,由於本身也沒研究透呢。github
顧名思義,不論是叫線性仍是叫順序,很明顯,就是一條數據一條數據的對比下去就好啦。面試
function SearchSeq($sk, $arr) { for ($i = 0; $i < count($arr); $i++) { if ($sk == $arr[$i]) { echo $i, PHP_EOL; break; } } echo "線性查找次數:" . $i, PHP_EOL; }
嗯,真的是連解釋都不想解釋了,這段代碼要是看不懂的話就先去複習下基本的循環和條件判斷語句吧!很明顯,一次線性查找的時間複雜度就是 O(N) 。算法
既然都這麼簡單,那麼咱們再直接給出折半查找的代碼。數據庫
function SearchBin($sk, $arr){ $left = 0; $right = count($arr) - 1; $i = 0; while ($left <= $right) { $i++; $mid = (int) (($left + $right) / 2); if ($arr[$mid] > $sk) { $right = $mid - 1; } else if ($arr[$mid] < $sk) { $left = $mid + 1; } else { echo $mid, PHP_EOL; break; } } echo "折半查找次數:" . $i, PHP_EOL; }
折半查找的前提是數據必須是有序的,這樣咱們就能夠根據數據問題的長度來獲取中間的數,而後跟要對比的數進行比較,若是小於這個數,就在前一半數據中查找,若是大於這個數,就在後一半部分中進行查找。一會看例子再詳細說明。編程
兩個算法其實都很簡單,咱們直接看看他們的運行狀況和效率區別。數組
$arr = [5, 6, 19, 25, 4, 33, 56, 77, 82, 81, 64, 37, 91, 23]; // 輸入 56 fscanf(STDIN, "%d", $searchKey); SearchSeq($searchKey, $arr); // 6 // 線性查找次數:6 sort($arr); print_r($arr); SearchBin($searchKey, $arr); // 8 // 折半查找次數:3
首先咱們定義了一個數組,其實就是隨便給了一些數據。而後輸入一個數據,查找它在數組中的位置。好比咱們在測試代碼中輸入了 56 ,線性查找是循環進行了 6 次,找到 56 所在的位置爲下標 6 的位置。數據結構
對於折半查找來講,咱們須要先給數組排序,這時 56 會排在下標爲 8 的位置,而在折半查找的循環中,咱們只循環了 3 次就找到了這個位置。是否是感受快了不少,一下就快了一倍。這可不是它的真正實力哦,折半查找的真實實力是 對數 級別的效率,也就是它的時間複雜度爲 O(logN) 。咱們先來結合上面的代碼看下它這三次循環都幹了什麼。數據結構和算法
第一次進入,mid 爲 6 (0+13=13,除2),下標爲 arr[6] 的值爲 3 ,比 56 小,因此 left = 6+1 = 7
第二輪循環,mid 爲 10(7+13=20,除2),下標爲 arr[10] 的值爲 77 ,比 56 大,因此 right = 10-1 = 9
第三輪循環,mid 爲 9(7+9=16,除2),下標爲 arr[8] 的值爲 56,結束
其實不少猜數字的遊戲也都是這麼玩的,好比給你一個範圍,0-100的數,猜他寫下的是哪一個數,最快最簡單的方法也就是這種折半查找的方式,咱們只須要最多 7 次就能夠猜出 100 之內的數。很明顯,這就是對數的威力。下面咱們再來看一個更直觀的,十萬個有序的數,咱們就找最後那一個數,看看順序查找和折半查找能有多大差距。
$arr = range(1, 100000); $searchKey = 100000; SearchSeq($searchKey, $arr); // 99999 // 線性查找次數:99999 SearchBin($searchKey, $arr); // 99999 // 折半查找次數:17
嗨不嗨,這就是對數的威力!!咱們須要 2 的 7 次方纔能覆蓋 100 之內的數,但咱們只須要 2 的 17 次方,就能覆蓋十萬之內的數,這個效率差距仍是隨着 N 的愈來愈大而愈來愈明顯的。
今天的內容是否是很簡單,雖然說內容簡單,可是咱們卻見識到了不一樣算法效率之間的巨大差別。固然,折半查找也有其自己的侷限,那就是數據必須是的序的,固然,在合適的狀況下咱們也能夠選用一個 O(logN) 的排序算法,這樣整體的時間複雜度就還能保持在對數級別了。總之,先掌握好這些簡單的內容,千萬別在面試的時候連這一關都過不了哦!
測試代碼: