到底什麼才是真正的空間複雜度?

彤哥讀原始碼發表於2020-07-26

file

前言

本篇文章收錄於專輯:http://dwz.win/HjK,點選解鎖更多資料結構與演算法的知識。

你好,我是彤哥,一個每天爬二十六層樓還不忘讀原始碼的硬核男人。

上一節,我們一起學習了複雜度分析的套路和常見的複雜度。

但是,我們的案例基本都是以時間複雜度為主,很少接觸到空間複雜度。

那麼,到底什麼才是真正的空間複雜度呢?在空間與時間發生衝突時又該如何權衡呢?

本節,我們就來解決這兩個問題。

來個例子

現在有一個演算法是這樣的,給定一個陣列,將陣列中每個元素都乘以2返回,我實現了下面兩種形式:

private static int[] multi1(int[] array) {
    int[] newArray = new int[array.length];
    for (int i = 0; i < array.length; i++) {
        newArray[i] = array[i] * 2;
    }
    return newArray;
}

private static int[] multi2(int[] array) {
    for (int i = 0; i < array.length; i++) {
        array[i] = array[i] * 2;
    }
    return array;
}

暫且不論這兩個演算法孰好孰壞,你來猜猜他們的空間複雜度各是多少?

你可能會說第一個演算法的空間複雜度為O(n),第二個演算法的空間複雜度為O(1)。

錯!兩個演算法的空間複雜度都是O(n)。

也不能說你完全錯了,因為大部分書籍或者資料都弄錯了。

是時候瞭解真正的空間複雜度了。

空間複雜度與額外空間複雜度

空間複雜度,是指一個演算法執行的過程佔用的空間,這個空間包括輸入引數的佔用空間和額外申請的空間。

所以,針對上面兩個演算法:

  • 第一個演算法,輸入引數n,額外空間n,兩者相加為2n,去除常數項,空間複雜度為O(n);
  • 第二個演算法,輸入引數n,額外空間0,兩者相加為n,空間複雜度為O(n)。

可以看到,使用空間複雜度很難判斷這兩個演算法的好壞,所以,誕生了另一個概念——額外空間複雜度。

額外空間複雜度,是指一個演算法執行過程中額外申請的空間。

使用額外空間複雜度,針對上面兩個演算法:

  • 第一個演算法,額外空間為n,額外空間複雜度為O(n);
  • 第二個演算法,額外空間為0,額外空間複雜度為O(1);

似乎沒見過有O(0)這種寫法。

可以看到,使用額外空間複雜度能夠很輕易地判斷兩個演算法的好壞(從空間佔用的角度)。

所以,是時候糾正錯誤的概念了,以後與人交流的時候請使用“額外空間複雜度”這個概念。

時間與空間的權衡

時間與空間往往是一組糾纏在一起的概念,就像很多小說中寫的一樣,主角最終領悟了時空法則,成為了最強者,小說結束。

在資料結構與演算法中也是一樣,時間與空間往往同時出現,而且經常朝著相反的方向運動。

比如,對於排序演算法:

  • 氣泡排序,時間複雜度O(n^2),空間複雜度O(1)
  • 歸併排序,時間複雜度O(nlogn),空間複雜度O(n)

所以,有兩種思想:以時間換空間,以空間換時間。

那麼,哪種演算法更好呢?

我認為,如果有時間、空間同時比較小的為最好,退而求其次,我選擇以空間換時間,畢竟,隨著計算機硬體技術地不斷髮展,空間越來越不值錢,而時間卻越來越值錢,所以,以空間換時間也是一種常用的思想,在我們後續的課程中會出現大量以空間換時間的案例。

想知道氣泡排序和歸併排序演算法的複雜度如何計算嗎?來呀,關注我吧。

後記

本節,我們從一個小例子入手,分析了兩種演算法的空間複雜度,並引出空間複雜度的真身——額外空間複雜度,最後,通過對比氣泡排序和歸併排序的時間複雜度和空間複雜度,得出了以空間換時間的思想。

到這裡,關於複雜度相關的章節就寫完了,從下一節開始,我們將進入常用資料結構與演算法的學習中,敬請期待。

P.S. 下週將進行晉升答辯,會停更幾天,敬請諒解。

關注公號主“彤哥讀原始碼”,解鎖更多原始碼、基礎、架構知識。

相關文章