10 道資料結構演算法題,不看答案你會幾道題

馬稱發表於2020-12-19

在這裡插入圖片描述

文章首將對應問題羅列,可以根據目錄找到感興趣的

  1. ArrayList 和 LinkedList 區別?結合資料結構說明
  2. B Tree 和 B+ Tree 區別?兩個 Tree 對比各自優勢
  3. Mysql 資料庫為什麼要使用樹結構充當索引結構
  4. LinkedList 的插入時間複雜度
  5. 氣泡排序的 3 種方式?哪種效能最好
  6. 氣泡排序的平均時間複雜度以及空間複雜度分別是多少
  7. 平衡二叉樹和紅黑樹的區別
  8. HashMap 中的 key 可以儲存可變引用型別麼?有什麼壞處?有什麼解決方案
  9. 什麼是Trie樹(字典樹)
  10. 為什麼 hashMap 的大小是 2 的 n 次方?(結合二進位制)

ArrayList 和 LinkedList 區別?結合資料結構說明

ArrayList 底層是使用動態陣列儲存的資料結構,如果查詢採用的定位方式是索引下標定位(還有根據元素定位 O(n)),時間複雜度為 O(1),所以查詢效率會很快,但是增、刪效率不好,如果是向尾部新增元素效率高

因為 ArrayList 類採用的儲存結構是連續的記憶體儲存,如果進行刪改元素將會對涉及到的陣列原有元素進行重排,所以特點是查詢快,增刪慢;並且在長度大於初始長度的話,會對陣列進行擴容

LinkedList 底層是使用雙向連結串列的形式進行儲存,查詢時間複雜度是 O(n),所以查詢會比較慢,但是增刪會很快,因為不涉及到對現有元素的重排

如果是增加元素的話,則對所增加元素的前序節點和後序節點改為插入位置的前後元素,將前後元素的前序節點和後序節點改為所增加的元素即可


B-Tree 和 B+ Tree 區別?兩個 Tree 對比各自優勢

B-tree 演算法減少定位記錄時所經歷的中間過程,從而加快存取速度。普遍運用在資料庫和檔案系統


B-Tree:

  1. 跟節點至少有兩個節點

  2. 首先從根節點進行二分查詢,如果找到則返回對應節點的 data,否則對相應區間的指標指向的節點遞迴進行查詢,直到找到節點或找到 null 指標,前者查詢成功,後者查詢失敗


B+Tree:

  1. 有 k 個子結點的結點必然有 k 個關鍵碼

  2. 非葉結點僅具有索引作用,跟記錄有關的資訊均存放在葉結點中

  3. 樹的所有葉結點構成一個有序連結串列,可以按照關鍵碼排序的次序遍歷全部記錄

這個優化的目的是為了提高區間訪問的效能


B-Tree 優點:

由於 B-Tree 的每一個節點都包含 key 和 value,因此經常訪問的元素可能離根節點更近,因此訪問也更迅速


B+Tree 優點:

  1. B+Tree 的非葉子結點只包含導航資訊,不包含實際的值,所有的葉子結點和相連的節點使用連結串列相連,便於區間查詢和遍歷

  2. 由於 B+Tree 在內部節點上不包含資料資訊,因此在記憶體頁中能夠存放更多的 key。 資料存放的更加緊密,具有更好的空間區域性性。因此訪問葉子節點上關聯的資料也具有更好的快取命中率

  3. B+Tree 的葉子結點都是相鏈的,因此對整棵樹的便利只需要一次線性遍歷葉子結點即可。而且由於資料順序排列並且相連,所以便於區間查詢和搜尋。而 B 樹則需要進行每一層的遞迴遍歷。相鄰的元素可能在記憶體中不相鄰,所以快取命中性沒有 B+Tree 好


Mysql 資料庫為什麼要使用樹結構充當索引結構

索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存的磁碟上

這樣的話,索引查詢過程中就要產生磁碟 I/O 消耗,相對於記憶體存取,I/O 存取的消耗要高几個數量級,所以評價一個資料結構作為索引的優劣最重要的指標就是在查詢過程中磁碟 I/O 操作次數的漸進複雜度。換句話說,索引的結構組織要儘量減少查詢過程中磁碟 I/O 的存取次數


LinkedList 的插入時間複雜度

如果執行 add(E e) 時間複雜度為 O(1),只需要獲取 last 元素,修改節點引用即可,如果使用 add(int index, E element)時間複雜度為 O(n),假如插入位置為 5,需要先查詢到第 5 個節點,然後只需要修改前後引用即可,不用進行元素移動

與 Arraylist 的最大特點,而是記憶體空間上的節省,因為 ArrayList 進行增刪元素時,會造成陣列元素重排,會將元素移動到新的陣列


氣泡排序的 3 種方式?

什麼是氣泡排序

  1. 將一個數與它後面的那一個數進行比較,如果前面>後面,則兩者交換位置

  2. 對陣列中的每一個數都進行這樣的操作,一個迴圈下來最大的數值就會到達陣列的最後面

  3. 再將陣列範圍縮小一個(即再次比較時不看陣列最後且最大的那個),再次迴圈上面的步驟

  4. 當陣列的範圍縮小到只剩下一個數的時候,那麼陣列就已經有序了,氣泡排序結束


最常見第一版氣泡排序

public static void sortFunc1(int[] arr) {
    if (arr == null || arr.length == 0) {
        return;
    }
    for (int i = arr.length - 1; i > 0; i--) {
        for (int j = 0; j < arr.length - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j + 1, j);
            }
        }
    }
}

第二版氣泡排序

public static void sortFunc2(int[] arr) {
    if (arr == null || arr.length == 0) {
        return;
    }
    boolean flag = true;
    while (flag) {
        flag = false;
        for (int i = arr.length - 1; i > 0; i--) {
            for (int j = 0; j < arr.length - 1; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j + 1, j);
                    flag = true;
                }
            }
        }
    }
}

第三版氣泡排序

public static void sortFunc2(int[] arr) {
    if (arr == null || arr.length == 0) {
        return;
    }
    int flag = arr.length - 1;
    while (flag > 0) {
        int end = flag;
        flag = 0;
        for (int j = 0; j < end; j++) {
            if (arr[j] > arr[j + 1]) {
                swap(arr, j + 1, j);
                flag = j;
            }
        }
    }
}

swap 交換演算法

public static void swap(int[] arr, int i, int j) {
    arr[i] = arr[i] ^ arr[j];
    arr[j] = arr[i] ^ arr[j];
    arr[i] = arr[i] ^ arr[j];
}

氣泡排序的平均時間複雜度以及空間複雜度分別是多少

平均時間複雜度:O(n2)

空間複雜度:O(1)


平衡二叉樹和紅黑樹的區別

  1. 紅黑樹放棄了追求完全平衡,追求大致平衡,在與平衡二叉樹的時間複雜度相差不大的情況下,保證每次插入最多隻需要三次旋轉就能達到平衡,實現起來也更為簡單
  2. 平衡二叉樹追求絕對平衡,條件比較苛刻,實現起來比較麻煩,每次插入新節點之後需要旋轉的次數不能預知

HashMap 中的 key 可以儲存可變引用型別麼?有什麼壞處?有什麼解決方案

可以定義為可變引用型別

假定一個 Student 物件為一個 hashMap 的 key,如果存入後,對物件進行了 set 操作,導致 hashCode 值改變,如果在使用 hashMap 的 get 操作查詢時,是查詢不到的

這種方式可以將 Student 物件的 hashCode 和 equals 方法來進行避免


什麼是Trie樹(字典樹)

trie,又稱字首樹,是一種有序樹,用於儲存關聯陣列,其中的鍵通常是字串。與二叉查詢樹不同,鍵不是直接儲存在節點中,而是由節點在樹中的位置決定。一個節點的所有子孫都有相同的字首,也就是這個節點對應的字串,而根節點對應空字串。一般情況下,不是所有的節點都有對應的值,只有葉子節點和部分內部節點所對應的鍵才有相關的值

在圖示中,鍵標註在節點中,值標註在節點之下。每一個完整的英文單詞對應一個特定的整數。Trie 可以看作是一個確定有限狀態自動機,儘管邊上的符號一般是隱含在分支的順序中的

鍵不需要被顯式地儲存在節點中。圖示中標註出完整的單詞,只是為了演示 trie 的原理

優點:利用字串的公共字首來節約儲存空間,最大限度地減少無謂的字串比較,查詢效率比雜湊表高

缺點:Trie樹是一種比較簡單的資料結構.理解起來比較簡單,正所謂簡單的東西也得付出代價.故Trie樹也有它的缺點,Trie樹的記憶體消耗非常大


為什麼 hashMap 的大小是 2 的 n 次方?(結合二進位制)

HashMap是根據key的hash值決定key放到哪個桶中,通過tab[i = (n - 1) & hash]公式計算得出

這裡的n是HashMap的容量,因為n永遠是2的次冪,所以n - 1通過二進位制表示,永遠都是末尾連續1的形式表示(如00001111、00000011),當(n - 1) 和hash做與運算時,會保留hash中後x位的1

例如00001111 & 10000011 = 00000011

這樣做的好處在於:

  • &運算速度快,至少比%取模運算快
  • 能保證索引值肯定在HashMap的容量大小範圍內
  • (n - 1) & hash的值是均勻分佈的,可以減少hash衝突

結言

由於作者水平有限, 歡迎大家能夠反饋指正文章中錯誤不正確的地方, 感謝 ?

小夥伴的喜歡就是對我最大的支援, 如果讀了文章有所收穫, 希望能夠 點贊、評論、關注三連!


推薦閱讀:

  1. 【強烈推薦】1w 字,18 張圖,徹底說清 springboot starter
  2. 【強烈推薦】謹慎使用 JDK 8 新特性並行流 ParallelStream
  3. 【強烈推薦】一文快速掌握 Redisson 如何實現分散式鎖原理
  4. 【大廠面試真題】JDK 執行緒池中如何不超最大執行緒數快速消費任務
  5. 【大廠面試真題】JDK 執行緒池如何保證核心執行緒不被銷燬

作者麻花,座標帝都 Java 後端研發,勵志成為架構師的一枚處女座程式設計師,專注高併發、框架底層原始碼、分散式等知識分享

相關文章