Java新手問題 01 算法和數據結構

Question: 何時該用數組型容器、何時該用鏈表型容器?

  • 數組數據結構:
    • 是將元素在內存中連續存放,因爲每一個元素佔用內存相同,能夠經過下標迅速訪問數組中任何元素。可是若是要在數組中增長一個元素,須要移動大量元素,在內存中空出一個元素的空間,而後將要增長的元素放在其中。一樣的道理,若是想刪除一個元素,一樣須要移動大量元素去填掉被移動的元素。若是應用須要快速訪問數據,不多或不插入和刪除元素,就應該用數組。
  • 鏈表數據結構:
    • 剛好相反,鏈表中的元素在內存中不是順序存儲的,而是經過存在元素中的指針聯繫到一塊兒。好比:上一個元素有個指針指到下一個元素,以此類推,直到最後一個元素。若是要訪問鏈表中一個元素,須要從第一個元素開始,一直找到須要的元素位置。可是增長和刪除一個元素對於鏈表數據結構就很是簡單了,只要修改元素中的指針就能夠了。若是應用須要常常插入和刪除元素你就須要用鏈表數據結構了
  • 數組型容器有:
    ArrayList
  • 鏈表型容器有:
    LinkedList
  • 使用原則:
    • 當數據刪除比較多,而查詢的狀況相對較少的狀況下使用鏈表型容器.
    • 當數據的查詢比較多,刪除/新增操做比較少的時候使用數組型容器.

Question: 什麼是散列函數?HashMap 的實現原理是什麼?

  • 散列函數是什麼:
    • 散列函數又叫哈希函數,就是把任意長度的輸入(又叫作預映射, pre-image),經過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出,而不可能從散列值來惟一的肯定輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。
  • HashMap內部是由Entry[]數組實現,根據key的hash值取模Entry[].length獲得數組下標(hash(key)%len).最終存儲方式是無序的。插入元素時,若是兩條Key落在同一個數組中(好比哈希值1和17取模16後都屬於第一個Entry),Entry用一個next屬性實現多個Entry以單向鏈表存放,先入Entry將next指向桶當前的Entry。

Question: 什麼是遞歸?若是你之前歷來沒寫過遞歸函數,嘗試着寫一個(好比用遞歸函數進行目錄樹遍歷)。

遞歸(英語:Recursion),又譯爲遞迴,在數學與計算機科學中,是指在函數的定義中使用函數自身的方法。遞歸一詞還較經常使用於描述以自類似方法重複事物的過程。例如,當兩面鏡子相互之間近似平行時,鏡中嵌套的圖像是以無限遞歸的形式出現的。也能夠理解爲自我複製的過程。java

  • 遞歸經典算法是:斐波那契數列

費波那契數列(意大利語:Successione di Fibonacci),又譯爲費波拿契數、斐波那契數列、費氏數列、黃金分割數列。
在數學上,費波那契數列是以遞歸的方法來定義:算法

f0 = 0
f1 = 1
fn = f(n-1) + f(n-2)

用文字來講,就是費波那契數列由0和1開始,以後的費波那契係數就是由以前的兩數相加而得出。首幾個費波那契係數是:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233……(OEIS中的數列A000045)數據庫

public class FibonacciDemo {
    public static void main(String[] args) {
        System.out.println(fibonacci(0, 1, 44));
    }
    public static int fibonacci(int cur, int next, int n) {
        if (n == 0) {
            return cur;
        } else {
            System.out.println(next);
            return fibonacci(next, cur + next, n - 1);
        }
    }

}

Question: 什麼是算法複雜度?

  • 算法複雜度是指計算解決問題所需的資源(時間和空間)
  • 爲何:
    • 若是一個問題的求解須要至關多的資源(不管用什麼算法),則被認爲是難解的。計算複雜性理論經過引入數學計算模型來研究這些問題以及定量計算解決問題所需的資源(時間和空間),從而將資源的肯定方法正式化了。其餘複雜性測度一樣被運用,好比通訊量(應用於通訊複雜性),電路中門的數量(應用於電路複雜性)以及中央處理器的數量(應用於並行計算)。計算複雜性理論的一個做用就是肯定一個能或不能被計算機求解的問題的所具備的實際限制。json

  • 怎麼樣:
    • 時間複雜度是一個函數,它定量描述了該算法的運行時間。這是一個表明算法輸入值的字符串的長度的函數。時間複雜度經常使用大O符號表述,不包括這個函數的低階項和首項係數。使用這種方式時,時間複雜度可被稱爲是漸近的,亦即考察輸入值大小趨近無窮時的狀況。例如,若是一個算法對於任何大小爲 n (必須比 n0 大)的輸入,它至多須要 5n3 + 3n 的時間運行完畢,那麼它的漸近時間複雜度是 O(n3)。
    • 空間複雜度(Space Complexity)是對一個算法在運行過程當中臨時佔用存儲空間大小的量度,記作S(n)=O(f(n))。好比直接插入排序的時間複雜度是O(n^2),空間複雜度是O(1) 。而通常的遞歸算法就要有O(n)的空間複雜度了,由於每次遞歸都要存儲返回信息。一個算法的優劣主要從算法的執行時間和所須要佔用的存儲空間兩個方面衡量。

Question: 你是否理解空間換時間的思想?

  • 好比在數據庫查詢時,將頻繁被訪問的數據存儲起來就是一種空間換時間的應用.
  • 在算法層面上,空間換時間,就好比HashMap,經過將數據以Hash數據分組存放的方式,以空間換取查詢的時間的加快.

Question: 寫一個針對整數數組的冒泡排序函數,看看你要修改幾回才能跑通。

import com.alibaba.fastjson.JSON;
public class BubbleSort {
    public static void main(String[] args) {
        int[] aa = new int[] { 2, 4, 3, 2, 5, 6 };
        for (int i = 0; i < aa.length; i++) {
            for (int j = i; j < aa.length; j++) {
                if (aa[i] < aa[j]) {
                    int temp = aa[i];
                    aa[i] = aa[j];
                    aa[j] = temp;
                }
            }
        }
        System.out.println(JSON.toJSONString(aa));
    }
}

Question: 寫一個針對整數數組的二分查找函數,看看你要修改幾回才能跑通。

public class BisectionSearch {
    public static void main(String[] args) {
        int[] aa = new int[] { 6, 5, 4, 3, 2, 2 };
        int target = 5;
        int start = 0;
        int end = aa.length - 1;
        int mid = (start + end) / 2;
        while (aa[mid] != target && end > start) {
            if (aa[mid] > target) {
                start = mid + 1;
            } else {
                end = mid - 1;
            }
            mid = (start + end) / 2;
        }
        if (aa[mid] == target) {
            System.out.println("找到target");
        }
    }
}

參考連接

相關文章
相關標籤/搜索