1. 數據結構中有哪些查找演算法
和二分查找性能接近的:既然可以二分查找,那麼關鍵字肯定可以滿足全序關系。那麼可以用二叉查找樹,一般的就是平攤O(logn),最壞O(n)。如果用平衡樹,如AVL,Treap,Splay等等,可以做到保持O(logn)的界。
比二分查找性能更優的:大概只有Hash了吧。如果Hash函數設計的好,基本可以認為是O(1)的。這個你最好系統學習一下,尤其是字元串的Hash函數。
2. 大數據最常用的演算法有哪些
奧地利符號計算研究所(Research Institute for Symbolic Computation,簡稱RISC)的Christoph Koutschan博士在自己的頁面上發布了一篇文章,提到他做了一個調查,參與者大多數是計算機科學家,他請這些科學家投票選出最重要的演算法,以下是這次調查的結果,按照英文名稱字母順序排序。
大數據等最核心的關鍵技術:32個演算法
1、A* 搜索演算法——圖形搜索演算法,從給定起點到給定終點計算出路徑。其中使用了一種啟發式的估算,為每個節點估算通過該節點的最佳路徑,並以之為各個地點排定次序。演算法以得到的次序訪問這些節點。因此,A*搜索演算法是最佳優先搜索的範例。
2、集束搜索(又名定向搜索,Beam Search)——最佳優先搜索演算法的優化。使用啟發式函數評估它檢查的每個節點的能力。不過,集束搜索只能在每個深度中發現最前面的m個最符合條件的節點,m是固定數字——集束的寬度。
3、二分查找(Binary Search)——在線性數組中找特定值的演算法,每個步驟去掉一半不符合要求的數據。
4、分支界定演算法(Branch and Bound)——在多種最優化問題中尋找特定最優化解決方案的演算法,特別是針對離散、組合的最優化。
5、Buchberger演算法——一種數學演算法,可將其視為針對單變數最大公約數求解的歐幾里得演算法和線性系統中高斯消元法的泛化。
6、數據壓縮——採取特定編碼方案,使用更少的位元組數(或是其他信息承載單元)對信息編碼的過程,又叫來源編碼。
7、Diffie-Hellman密鑰交換演算法——一種加密協議,允許雙方在事先不了解對方的情況下,在不安全的通信信道中,共同建立共享密鑰。該密鑰以後可與一個對稱密碼一起,加密後續通訊。
8、Dijkstra演算法——針對沒有負值權重邊的有向圖,計算其中的單一起點最短演算法。
9、離散微分演算法(Discrete differentiation)。
10、動態規劃演算法(Dynamic Programming)——展示互相覆蓋的子問題和最優子架構演算法
11、歐幾里得演算法(Euclidean algorithm)——計算兩個整數的最大公約數。最古老的演算法之一,出現在公元前300前歐幾里得的《幾何原本》。
12、期望-最大演算法(Expectation-maximization algorithm,又名EM-Training)——在統計計算中,期望-最大演算法在概率模型中尋找可能性最大的參數估算值,其中模型依賴於未發現的潛在變數。EM在兩個步驟中交替計算,第一步是計算期望,利用對隱藏變數的現有估計值,計算其最大可能估計值;第二步是最大化,最大化在第一步上求得的最大可能值來計算參數的值。
13、快速傅里葉變換(Fast Fourier transform,FFT)——計算離散的傅里葉變換(DFT)及其反轉。該演算法應用范圍很廣,從數字信號處理到解決偏微分方程,到快速計算大整數乘積。
14、梯度下降(Gradient descent)——一種數學上的最優化演算法。
15、哈希演算法(Hashing)。
16、堆排序(Heaps)。
17、Karatsuba乘法——需要完成上千位整數的乘法的系統中使用,比如計算機代數系統和大數程序庫,如果使用長乘法,速度太慢。該演算法發現於1962年。
18、LLL演算法(Lenstra-Lenstra-Lovasz lattice rection)——以格規約(lattice)基數為輸入,輸出短正交向量基數。LLL演算法在以下公共密鑰加密方法中有大量使用:背包加密系統(knapsack)、有特定設置的RSA加密等等。
19、最大流量演算法(Maximum flow)——該演算法試圖從一個流量網路中找到最大的流。它優勢被定義為找到這樣一個流的值。最大流問題可以看作更復雜的網路流問題的特定情況。最大流與網路中的界面有關,這就是最大流-最小截定理(Max-flow min-cut theorem)。Ford-Fulkerson 能找到一個流網路中的最大流。
20、合並排序(Merge Sort)。
21、牛頓法(Newton』s method)——求非線性方程(組)零點的一種重要的迭代法。
22、Q-learning學習演算法——這是一種通過學習動作值函數(action-value function)完成的強化學習演算法,函數採取在給定狀態的給定動作,並計算出期望的效用價值,在此後遵循固定的策略。Q-leanring的優勢是,在不需要環境模型的情況下,可以對比可採納行動的期望效用。
23、兩次篩法(Quadratic Sieve)——現代整數因子分解演算法,在實踐中,是目前已知第二快的此類演算法(僅次於數域篩法Number Field Sieve)。對於110位以下的十位整數,它仍是最快的,而且都認為它比數域篩法更簡單。
24、RANSAC——是「RANdom SAmple Consensus」的縮寫。該演算法根據一系列觀察得到的數據,數據中包含異常值,估算一個數學模型的參數值。其基本假設是:數據包含非異化值,也就是能夠通過某些模型參數解釋的值,異化值就是那些不符合模型的數據點。
25、RSA——公鑰加密演算法。首個適用於以簽名作為加密的演算法。RSA在電商行業中仍大規模使用,大家也相信它有足夠安全長度的公鑰。
26、Sch?nhage-Strassen演算法——在數學中,Sch?nhage-Strassen演算法是用來完成大整數的乘法的快速漸近演算法。其演算法復雜度為:O(N log(N) log(log(N))),該演算法使用了傅里葉變換。
27、單純型演算法(Simplex Algorithm)——在數學的優化理論中,單純型演算法是常用的技術,用來找到線性規劃問題的數值解。線性規劃問題包括在一組實變數上的一系列線性不等式組,以及一個等待最大化(或最小化)的固定線性函數。
28、奇異值分解(Singular value decomposition,簡稱SVD)——在線性代數中,SVD是重要的實數或復數矩陣的分解方法,在信號處理和統計中有多種應用,比如計算矩陣的偽逆矩陣(以求解最小二乘法問題)、解決超定線性系統(overdetermined linear systems)、矩陣逼近、數值天氣預報等等。
29、求解線性方程組(Solving a system of linear equations)——線性方程組是數學中最古老的問題,它們有很多應用,比如在數字信號處理、線性規劃中的估算和預測、數值分析中的非線性問題逼近等等。求解線性方程組,可以使用高斯—約當消去法(Gauss-Jordan elimination),或是柯列斯基分解( Cholesky decomposition)。
30、Strukturtensor演算法——應用於模式識別領域,為所有像素找出一種計算方法,看看該像素是否處於同質區域( homogenous region),看看它是否屬於邊緣,還是是一個頂點。
31、合並查找演算法(Union-find)——給定一組元素,該演算法常常用來把這些元素分為多個分離的、彼此不重合的組。不相交集(disjoint-set)的數據結構可以跟蹤這樣的切分方法。合並查找演算法可以在此種數據結構上完成兩個有用的操作:
查找:判斷某特定元素屬於哪個組。
合並:聯合或合並兩個組為一個組。
32、維特比演算法(Viterbi algorithm)——尋找隱藏狀態最有可能序列的動態規劃演算法,這種序列被稱為維特比路徑,其結果是一系列可以觀察到的事件,特別是在隱藏的Markov模型中。
以上就是Christoph博士對於最重要的演算法的調查結果。你們熟悉哪些演算法?又有哪些演算法是你們經常使用的?
3. 對比順序查找、二分查找和哈希查找演算法,它們各自的特點是什麼
順序查找,二分查找和哈希查找演算法,它們各自的特點是:
1.對比順序查找的特點就是從表的第一個元素開始一個一個向下查找,如果有和目標一致的元素,查找成功;如果到最後一個元素仍沒有目標元素,則查找失敗。
2.二分查找的特點就是從表中間開始查找目標元素。如果找到一致元素,則查舉羨找成功。如果中間元素比正蠢拍目標元素小,則仍用二分查找方法查找表的後半部分(表是遞增排列的),反之中間元素比目標元素大,則查找表的前半部分。
3.哈希演算法的特點是是使用給定數據構造哈希表,然後檔芹在哈希表上進行查找的一種演算法。先給定一個值,然後根據哈希函數求得哈希地址,再根據哈希地址查找到要找的元素。是通過數據元素的存儲地址進行查找的一種演算法。
4. 查找演算法和枚舉演算法差別
不對
枚舉是在范圍內查找所有可能解,不是找到就結束;
順序查找是假設在數組范圍內找key,找到就結束,不一定到數據結束。也就是,如果數組中的第一個數據就是我們要找的key,那麼找到了,不再繼續找第2個。
5. 談談幾種接觸搜索演算法的比較麻煩告訴我
接觸分析計算主要是接觸界面的搜尋方法和法向接觸力的計算問題.
常見的有主從面法、級域法和一體化演算法 是接觸點的搜索演算法,這三種演算法中,最早的是主從面法,主從面法中從節點不允許穿透主動面,但主動面上的接觸點可以穿透從動面。故主從面法只需搜尋與主動面接觸的節點。主從面法的一個缺陷是——不能處理同一個接觸面內發生的情況,比如子接觸問題。與其他兩種方法相比,主從面法只考慮接觸體中一半的接觸點,所以其計算工作量是比較小的。級域法在相互靠近的接觸塊中尋找接觸對;一體化演算法總是在所有的接觸塊中尋找。由於計算方法的不同,這三種方法計算時間依賴於接觸面的大小。另一方面主從法之所以被廣泛採用,是他的缺桐演算法很成熟,編程也容易,而級域法需要從高到低逐級進行,編程就很困難,而且其矢量化運算能凳扮凱力也不行。
所以總體來說,一體化演算法是最優越的。
除了這三種演算法,還有一些別的演算法:比如 BCM,邊界搜索,近些年一些智能演算法也被廣泛引入進來!
除了接觸點的搜尋演算法,常用的接觸力演算法為:拉格朗日乘子法和罰函數法。拉格朗日乘子法不允許接觸邊界的互相穿透,能准確描述幾何約束條件,是一種精確的接觸力演算法,但它與顯式演算法不相容,要求特殊的數值處理。但該方法在棗喚每個接觸點處要求引入乘子,導致系統自由度的增加,使計算效率降低。而罰函數法允許接觸面之間的互相穿透,並通過罰子將接觸力大小和接觸邊界的穿透量聯系起來,接觸力正比於邊界穿透量。此方法比較簡單單也適合於顯式演算法,能在系統自由度不增加的情況下進行數值求解。但它影響顯式演算法中的臨界時間步長。罰因子的好壞還影響計算結果的可靠性。
6. 數據結構中,查找演算法最優的是哪一種
折半查找法的平均查找長度隨n增大而呈現對數增長趨勢,因此折半查找法為最優查找演算法
7. 深度優先搜索和廣度優先搜索、A星演算法三種演算法的區別和聯系
在說它之前先提提狀態空間搜索。狀態空間搜索,如果按專業點的說法就是將問題求解過程表現為從初始狀態到目標狀態尋找這個路徑的過程。通俗點說,就是 在解一個問題時,找到一條解題的過程可以從求解的開始到問題的結果(好象並不通俗哦)。由於求解問題的過程中分枝有很多,主要是求解過程中求解條件的不確 定性,不完備性造成的,使得求解的路徑很多這就構成了一個圖,我們說這個圖就是狀態空間。問題的求解實際上就是在這個圖中找到一條路徑可以從開始到結果。 這個尋找的過程就是狀態空間搜索。 常用的狀態空間搜索有深度優先和廣度優先。廣度優先是從初始狀態一層一層向下找,直到找到目標為止。深度優先是按照一定的順序前查找完一個分支,再查找另一個分支,以至找到目標為止。這兩種演算法在數據結構書中都有描述,可以參看這些書得到更詳細的解釋。 前面說的廣度和深度優先搜索有一個很大的缺陷就是他們都是在一個給定的狀態空間中窮舉。這在狀態空間不大的情況下是很合適的演算法,可是當狀態空間十分大,且不預測的情況下就不可取了。他的效率實在太低,甚至不可完成。在這里就要用到啟發式搜索了。 啟發中的估價是用估價函數表示的,如: f(n) = g(n) + h(n) 其中f(n) 是節點n的估價函數,g(n)實在狀態空間中從初始節點到n節點的實際代價,h(n)是從n到目標節點最佳路徑的估計代價。在這里主要是h(n)體現了搜 索的啟發信息,因為g(n)是已知的。如果說詳細點,g(n)代表了搜索的廣度的優先趨勢。但是當h(n) >> g(n)時,可以省略g(n),而提高效率。這些就深了,不懂也不影響啦!我們繼續看看何謂A*演算法。 2、初識A*演算法 啟發式搜索其實有很多的演算法,比如:局部擇優搜索法、最好優先搜索法等等。當然A*也是。這些演算法都使用了啟發函數,但在具體的選取最佳搜索節點時的 策略不同。象局部擇優搜索法,就是在搜索的過程中選取「最佳節點」後舍棄其他的兄弟節點,父親節點,而一直得搜索下去。這種搜索的結果很明顯,由於舍棄了 其他的節點,可能也把最好的節點都舍棄了,因為求解的最佳節點只是在該階段的最佳並不一定是全局的最佳。最好優先就聰明多了,他在搜索時,便沒有舍棄節點 (除非該節點是死節點),在每一步的估價中都把當前的節點和以前的節點的估價值比較得到一個「最佳的節點」。這樣可以有效的防止「最佳節點」的丟失。那麼 A*演算法又是一種什麼樣的演算法呢?其實A*演算法也是一種最好優先的演算法。只不過要加上一些約束條件罷了。由於在一些問題求解時,我們希望能夠求解出狀態空 間搜索的最短路徑,也就是用最快的方法求解問題,A*就是干這種事情的!我們先下個定義,如果一個估價函數可以找出最短的路徑,我們稱之為可採納性。A* 演算法是一個可採納的最好優先演算法。A*演算法的估價函數可表示為: f'(n) = g'(n) + h'(n) 這里,f'(n)是估價函數,g'(n)是起點到終點的最短路徑值,h'(n)是n到目標的最斷路經的啟發值。由於這個f'(n)其實是無法預先知道 的,所以我們用前面的估價函數f(n)做近似。g(n)代替g'(n),但 g(n)>=g'(n)才可(大多數情況下都是滿足的,可以不用考慮),h(n)代替h'(n),但h(n)<=h'(n)才可(這一點特別 的重要)。可以證明應用這樣的估價函數是可以找到最短路徑的,也就是可採納的。我們說應用這種估價函數的最好優先演算法就是A*演算法。哈。你懂了嗎?肯定沒 懂。接著看。 舉一個例子,其實廣度優先演算法就是A*演算法的特例。其中g(n)是節點所在的層數,h(n)=0,這種h(n)肯定小於h'(n),所以由前述可知廣度優先演算法是一種可採納的。實際也是。當然它是一種最臭的A*演算法。 再說一個問題,就是有關h(n)啟發函數的信息性。h(n)的信息性通俗點說其實就是在估計一個節點的值時的約束條件,如果信息越多或約束條件越多則排除 的節點就越多,估價函數越好或說這個演算法越好。這就是為什麼廣度優先演算法的那麼臭的原因了,誰叫它的h(n)=0,一點啟發信息都沒有。但在游戲開發中由 於實時性的問題,h(n)的信息越多,它的計算量就越大,耗費的時間就越多。就應該適當的減小h(n)的信息,即減小約束條件。但演算法的准確性就差了,這 里就有一個平衡的問題。可難了,這就看你的了! 好了我的話也說得差不多了,我想你肯定是一頭的霧水了,其實這是寫給懂A*演算法的同志看的。哈哈。你還是找一本人工智慧的書仔細看看吧!我這幾百字是不足以將A*演算法講清楚的。只是起到拋磚引玉的作用希望大家熱情參與嗎。
8. 常見查找和排序演算法
查找成功最多要n 次,平均(n+1)/2次, 時間復雜度為O(n) 。
優點:既適用順序表也適用單鏈表,同時對表中元素順序無要求,給插入帶來方便,只需插入表尾即可。
缺點:速度較慢。
改進:在表尾設置一個崗哨,這樣不用去循環判斷數組下標是否越界,因為最後必然成立。
適用條件:
二分查找的判定樹不僅是二叉排序樹,而且是一棵理想平衡樹。 時間復雜度為O(lbn) 。
循環實現
遞歸實現
待排序的元素需要實現 Java 的 Comparable 介面,該介面有 compareTo() 方法,可以用它來判斷兩個元素的大小關系。
從數組中選擇最小元素,將它與數組的第一個元素交換位置。再從數組剩下的元素中選擇出最小的元素,將它與數組的第二個元素交換位置。不斷進行這樣的操作,直到將整個數組排序。
選擇排序需要 ~N2/2 次比較和 ~N 次交換,==它的運行時間與輸入無關==,這個特點使得它對一個已經排序的數組也需要這么多的比較和交換操作。
從左到右不斷 交換相鄰逆序的元素 ,在一輪的循環之後,可以讓未排序的最大元素上浮到右側。
在一輪循環中,如果沒有發生交換,那麼說明數組已經是有序的,此時可以直接退出。
每次都 將當前元素插入到左側已經排序的數組中 ,使得插入之後左側數組依然有序。
對於數組 {3, 5, 2, 4, 1},它具有以下逆序:(3, 2), (3, 1), (5, 2), (5, 4), (5, 1), (2, 1), (4, 1),插入排序每次只能交換相鄰元素,令逆序數量減少 1,因此插入排序需要交換的次數為逆序數量。
==插入排序的時間復雜度取決於數組的初始順序,如果數組已經部分有序了,那麼逆序較少,需要的交換次數也就較少,時間復雜度較低==。
對於大規模的數組,插入排序很慢,因為它只能交換相鄰的元素,每次只能將逆序數量減少 1。希爾排序的出現就是為了解決插入排序的這種局限性,它通過交換不相鄰的元素,每次可以將逆序數量減少大於 1。
希爾排序使用插入排序對間隔 h 的序列進行排序。通過不斷減小 h,最後令 h=1,就可以使得整個數組是有序的。
希爾排序的運行時間達不到平方級別,使用遞增序列 1, 4, 13, 40, ... 的希爾排序所需要的比較次數不會超過 N 的若干倍乘於遞增序列的長度。後面介紹的高級排序演算法只會比希爾排序快兩倍左右。
歸並排序的思想是將數組分成兩部分,分別進行排序,然後歸並起來。
歸並方法將數組中兩個已經排序的部分歸並成一個。
將一個大數組分成兩個小數組去求解。
因為每次都將問題對半分成兩個子問題,這種對半分的演算法復雜度一般為 O(NlogN)。
先歸並那些微型數組,然後成對歸並得到的微型數組。
取 a[l] 作為切分元素,然後從數組的左端向右掃描直到找到第一個大於等於它的元素,再從數組的右端向左掃描找到第一個小於它的元素,交換這兩個元素。不斷進行這個過程,就可以保證左指針 i 的左側元素都不大於切分元素,右指針 j 的右側元素都不小於切分元素。當兩個指針相遇時,將切分元素 a[l] 和 a[j] 交換位置。
快速排序是原地排序,不需要輔助數組,但是遞歸調用需要輔助棧。
快速排序最好的情況下是每次都正好將數組對半分,這樣遞歸調用次數才是最少的。這種情況下比較次數為 CN=2CN/2+N,復雜度為 O(NlogN)。
最壞的情況下,第一次從最小的元素切分,第二次從第二小的元素切分,如此這般。因此最壞的情況下需要比較 N2/2。為了防止數組最開始就是有序的,在進行快速排序時需要隨機打亂數組。
因為快速排序在小數組中也會遞歸調用自己,對於小數組,插入排序比快速排序的性能更好,因此在小數組中可以切換到插入排序。
最好的情況下是每次都能取數組的中位數作為切分元素,但是計算中位數的代價很高。一種折中方法是取 3 個元素,並將大小居中的元素作為切分元素。
對於有大量重復元素的數組,可以將數組切分為三部分,分別對應小於、等於和大於切分元素。
三向切分快速排序對於有大量重復元素的隨機數組可以在線性時間內完成排序。
快速排序的 partition() 方法,會返回一個整數 j 使得 a[l..j-1] 小於等於 a[j],且 a[j+1..h] 大於等於 a[j],此時 a[j] 就是數組的第 j 大元素。
可以利用這個特性找出數組的第 k 大的元素。
該演算法是線性級別的,假設每次能將數組二分,那麼比較的總次數為 (N+N/2+N/4+..),直到找到第 k 個元素,這個和顯然小於 2N。
堆中某個節點的值總是大於等於其子節點的值,並且堆是一顆完全二叉樹。
堆可以用數組來表示,這是因為堆是完全二叉樹,而完全二叉樹很容易就存儲在數組中。位置 k 的節點的父節點位置為 k/2,而它的兩個子節點的位置分別為 2k 和 2k+1。這里不使用數組索引為 0 的位置,是為了更清晰地描述節點的位置關系。
在堆中,當一個節點比父節點大,那麼需要交換這個兩個節點。交換後還可能比它新的父節點大,因此需要不斷地進行比較和交換操作,把這種操作稱為上浮。
類似地,當一個節點比子節點來得小,也需要不斷地向下進行比較和交換操作,把這種操作稱為下沉。一個節點如果有兩個子節點,應當與兩個子節點中最大那個節點進行交換。
將新元素放到數組末尾,然後上浮到合適的位置。
從數組頂端刪除最大的元素,並將數組的最後一個元素放到頂端,並讓這個元素下沉到合適的位置。
把最大元素和當前堆中數組的最後一個元素交換位置,並且不刪除它,那麼就可以得到一個從尾到頭的遞減序列,從正向來看就是一個遞增序列,這就是堆排序。
一個堆的高度為logN,因此在堆中插入元素和刪除最大元素的復雜度都為 logN。
對於堆排序,由於要對 N 個節點進行下沉操作,因此復雜度為 NlogN。
堆排序是一種原地排序,沒有利用額外的空間。
現代操作系統很少使用堆排序,因為它無法利用局部性原理進行緩存,也就是數組元素很少和相鄰的元素進行比較和交換。
計數排序的核心在於將輸入的數據值轉化為鍵存儲在額外開辟的數組空間中。作為一種線性時間復雜度的排序,==計數排序要求輸入的數據必須是有確定范圍的整數==。
當輸入的元素是 n 個 0 到 k 之間的整數時,它的==運行時間是 O(n + k)==。計數排序不是比較排序,排序的速度快於任何比較排序演算法。由於用來計數的數組C的長度取決於待排序數組中數據的范圍(等於待排序數組的最大值與最小值的差加上1),這使得計數排序對於數據范圍很大的數組,需要大量時間和內存。比較適合用來排序==小范圍非負整數數組的數組==。
桶排序是計數排序的升級版。它利用了函數的映射關系,高效與否的關鍵就在於這個映射函數的確定。為了使桶排序更加高效,我們需要做到這兩點:
同時,對於桶中元素的排序,選擇何種比較排序演算法對於性能的影響至關重要。
當輸入數據均勻分配到每一個桶時最快,當都分配到同一個桶時最慢。
實間復雜度N*K
快速排序是最快的通用排序演算法,它的內循環的指令很少,而且它還能利用緩存,因為它總是順序地訪問數據。它的運行時間近似為 ~cNlogN,這里的 c 比其它線性對數級別的排序演算法都要小。
使用三向切分快速排序,實際應用中可能出現的某些分布的輸入能夠達到線性級別,而其它排序演算法仍然需要線性對數時間。