1. 程式人生 > >php tree(九)資料結構/ 演算法

php tree(九)資料結構/ 演算法

資料結構 

  1. 常見資料結構與演算法整理總結(上)
    • 線性表(陣列,連結串列),棧與佇列,樹,二叉樹,二叉查詢/搜尋/排序樹,平衡二叉樹,紅黑樹,圖。
    • 陣列和連結串列
      型別 分配記憶體方式 記憶體連續性 位置 查詢複雜度 插入/刪除
      陣列 靜態 連續
      • 優點:可以通過下標來訪問元素
      • 缺點:若插入/刪除元素,要將其後所有元素移動位置
      O(1) O(n)
      連結串列 動態 不連續 O(n) O(1)
    • 堆和棧佇列、堆、棧、堆疊的區別?
      佇列 有一個入口和一個出口,先進先出
      就像一個箱子,後進先出
      請求作業系統分配記憶體,效率低
  2. 資料結構中常用的樹
    遍歷 都是相對於根節點來說的,左節點總是在右節點前面
    • 先序:根-左-右
    • 中序:左-根-右
    • 後序:左-右-根
    表示一個節點最多能有多少個子節點,如二叉樹的階數就是2。
    指父結點下面有幾個孩子結點。
    滿二叉樹 一棵深度為k且有2k-1(2的k次冪減1)個結點的二叉樹稱為滿二叉樹。
    完全二叉樹 每一個結點都與深度為k的滿二叉樹中編號從1至n的結點一一對應。
    二叉樹 每個結點至多隻有2棵子樹,二叉樹的子樹有左右之分,次序不能顛倒。
    • 型別:滿二叉樹,完全二叉樹。
    1. 二叉樹第 i 層上最多有2i-1個節點
    2. 深度為 k 的二叉樹,最多有2k - 1個節點
    3. 對於任意一顆二叉樹T,如果其終端節點數為n1度數為2的節點數為n2 則 n1 = n2 + 1
    4. 具有n個節點的完全二叉樹深度為[ log2n] + 1;
    樹和二叉樹
    1. 二叉樹每個節點最多有2個子節點,樹無限制。
    2. 二叉樹有序。子樹分為左子樹和右子樹,即使某節點只有一棵子樹,也要指明是左子樹還是右子樹。
    3. 二叉樹可以是空。樹不能為空,至少有一個節點。
    • BST二叉搜尋樹、AVL平衡二叉樹、RBT紅黑樹、B-樹、B+樹、B*樹AVL 紅黑樹 B(+)樹 跳錶 字典樹 應用場景及分析
      型別 特點 缺點 應用
      二叉查詢樹
      • 節點有序,利於二分查詢。
      • 左子樹小於它的根結點,右子樹大於它的根結點,沒有值相等的結點。
      • 因為不一定平衡,有可能退化成線性表,搜尋效能不佳
       
      • 用於搜尋
      平衡二叉樹
      • 是二叉查詢樹
      • 嚴格要求平衡。左子樹和右子樹的深度之差的絕對值不超過1。
      • 查詢效能好,維護成本高
      • 適合用於插入刪除次數比較少,但查詢多的情況。 
      紅黑樹
      • 通過任何一條從根到葉子的簡單路徑上各個節點的顏色進行約束,確保沒有一條路徑會比其他路徑長2倍,因而是近似平衡的。
      • 相對於AVL樹來說,旋轉保持平衡次數較少。用於搜尋時,插入刪除次數多的情況下我們使用紅黑樹來取代AVL。 
      • 更新資料時,紅黑樹有個平衡的過程,牽涉到大量的節點,爭鎖的代價相對高。效能不如跳躍表。
      • epoll 在核心中的實現,用紅黑樹來管理事件塊
      • nginx中,用紅黑樹來管理timer等
      • Java中的TreeMap實現
      B樹/B+樹
      • 多路查詢樹,分支多層數少,可以有效減少磁碟IO次數。
      • 相當於AVL更適合於檔案系統。
      null
      • 磁碟IO是非常耗時的,為檔案系統、資料庫系統而生。
      跳躍表
      • 更新資料時,跳躍表需要更新的部分少,鎖的東西少,效能佳
      null
      • redis sorted set
  3. 什麼是B-Tree什麼是B+Tree
    資料庫索引
    • 索引儲存在磁碟上,資料量比較大時,索引大小也跟著增長,達到幾個G。
    • 利用索引進行查詢時,不可能把索引全部載入到記憶體,只能逐一載入每個磁碟頁,這裡的磁碟頁就對應索引樹的節點。
    b樹
    1. 關鍵字集合分佈在整顆樹中;
    2. 任何一個關鍵字出現且只出現在一個結點中;
    3. 搜尋有可能在非葉子結點結束;
    4. 其搜尋效能等價於在關鍵字全集內做一次二分查詢;
    5. 自動層次控制
    b+樹
    • 單節點可以儲存更多的元素。使得查詢磁碟IO次數更少。
    • 所有查詢都要查詢到葉子節點,查詢效能穩定。
    • 所有葉子節點形成有序連結串列,便於範圍查詢。
  4. 資料結構之雜湊表大多數分散式儲存系統要麼實現一個分散式Hash表,要麼實現分散式B+樹
  5. Redis為什麼用跳錶而不用平衡樹?
    • 跳躍表特點
      • 在有序連結串列的基礎上發展而來的多層連結串列。
      • 間隔一定元素增加指標,原連結串列足夠長時,能跳過很多下層節點,大大加快查詢速度。
      • 上層連結串列節點個數,是下曾節點個數一半,非常類似一個二分查詢。時間複雜度O(log n)。
      • 然後對於刪除和插入,採用隨機生成層數,保證插入或者刪除只需要修改結點前後指標,效能優於平衡樹。
      • 層隨機數,不超過一個最大值。
    • 對比
      型別 元素是否有序 平均複雜度/ 單key查詢 範圍查詢 記憶體佔用 演算法實現難度 優點
      平衡樹 O(log n) 複雜 複雜 平衡
      雜湊表 否。所以不支援範圍查詢 O(1) 不支援 大(需要事先分配足夠的記憶體儲存散列表) 取決於雜湊函式 查詢快
      跳躍表 O(log n) 簡單 靈活 簡單 更新資料時,跳躍表需要更新的部分少,鎖的東西少
    • sorted set資料結構實現
      • 資料較少時,由ziplist實現。
      • 資料較多時,由dict + skiplist實現。dict維護資料到分數的對應,skiplist用來根據分數範圍查詢資料。
      • 分數相同時,根據資料內容進行字典排序。
      • 第一層量表不是單向連結串列,而是一個雙向連結串列,為了方便以倒序方式獲取一個範圍內元素。只有第一層連結串列時雙向連結串列。

演算法

  1. 常見資料結構與演算法整理總結(下)
  2. 常見排序演算法八大排序演算法
    大類 小類 演算法
    選擇 選擇
    • 每個數(當前數)和之後的每個數比較,每次記下小數的位置,然後交換當前數和最小數的位置
    堆排序 特點:
    • 堆是具有以下性質的完全二叉樹:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆;
    • 或者每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。
    構造步驟:
    • 若升序,構建大頂堆,
    • 堆頂元素和末尾元素交換,末尾表示排好的序列。
    • 對前面元素重複前2步,
    • 直到整個序列有序。
    插入 直接插入
    • 從第一個數開始,之後每個數插入前面假定排好序的位置。根據如何確定插入位置,分為直接插入(遍歷)和二分查詢插入
    希爾排序 改進的插入排序。按步長進行分組,每組內的元素進行插入排序。逐步減小步長,直到為1,即為普通的插入排序的情況。前面的步驟可以將所有元素變成基本是排好序的,較少要移動的元素。
    交換 冒泡
    • 每個數與下一個相鄰的數比較,大的往後放。每輪下來,產生一個最大數放在最後位置(前插在後面最大數序列中)
    快速
    • 選擇基準數(第一個也可以),比它大的放右邊容器,小的放左邊,左邊和右邊數做同樣處理(遞迴),然後合併左、基準數、右邊數即得
    歸併排序
    • 分而治之
    基數排序 按個位大小排序、按十位大小排序、百位......
    總結 平均時間複雜度:nlogn:快速、堆、歸併。關鍵字隨機分佈時,快速排序平均時間最短
  3. 查詢
    順序查詢
    二分查詢
    • 兩個名字(二分查詢、折半查詢)
    • 優點三個(比較次數少、查詢速度快、平均效能好)
    • 缺點兩個(待查詢表為有序表、插入刪除困難),用數字表示就是232。8
    逐步縮小目標陣列的邊界。
    • 初始傳入待查詢陣列的左右邊界分別為0和陣列長度-1。
    • 邊界檢查:如果左邊界>右邊界,則返回“找不到該數”,退出,
    • 將待查詢數與中間位置(向下取整,只要能定出界限,無所謂多1還是少1)數比較,
    • 如果比中間位置數大,則繼續在中間位置右邊的數中查詢(執行遞迴,左邊界變成中間位置+1),
    • 如果比中間位置數小,則繼續在中間位置左邊的數中查詢(執行遞迴,右邊界變成中間位置-1),
    • 否則相等的話,表示找到待查詢的數,退出。
    • 程式碼實現:遞迴與非遞迴實現
    分塊查詢 是前兩者結合,分塊有序,塊內無序,插入和刪除無需大量移動記錄
    散列表
  4. 程式碼:常用排序和兩個查詢
  5. 實戰:
    1. 劍指offer中的演算法題資料結構和演算法面試題
    2. 百錢買雞。滿足一定條件,資料在一定範圍。制定for迴圈,剩下的事交給計算機。制定等式,接下來思路,讓變數變化,所以制定for迴圈。
    3. 約瑟夫環。遞迴演算法和公式法。
    4. 斐波那契數列。遞迴法和迭代法
    5. TopKbitmap計數,求TopK最快的方法
      常規
      1. 全域性排序,再取前k個。複雜度:n*lg(n)(快速排序)。
      2. 區域性排序,只對最大k個排序。使用冒泡排出k個最大數。複雜度:n*k(冒泡:n*n)。
      3. 堆排序。只找到TopK,不排序TopK。複雜度:n*lg(k)(堆排序:n*lg(n))。
      4. 分治,每個分支都要遞迴,例如快速排序。不懂。
      5. 減治,只要遞迴一個分支,例如二分查詢。不懂。
      6. 隨機選擇+partition。不懂。
      bitmap 元素沒有重複
      • 相應位的元素存在則存1,否則存0。
      • 掃描一次所有n個元素,生成bitmap,時間複雜度O(n)。
      • 生成後,去TopK只需要找到最高位的k個bit即可。
      元素有重複
      • 每個元素的一個bit變成一個計數,
      • 找TopK的過程:從高位往低位掃描,得到count之和等於k,對應的bit就是TopK所求。
    6. 全排列演算法
    7. 天平稱球
    8. 二進位制和三進位制的妙用
    9. PHP實現的演算法合集