算法復(fù)雜度分析

復(fù)雜度分析:

數(shù)據(jù)結(jié)構(gòu)和算法解決的兩大問題:快和省。運(yùn)行快,儲(chǔ)存省。

復(fù)雜度分析是算法學(xué)習(xí)的精髓:時(shí)間復(fù)雜度,空間復(fù)雜度。

事后統(tǒng)計(jì)法有很大局限性:

  1. 測(cè)試結(jié)果依賴測(cè)試環(huán)境
  2. 測(cè)試結(jié)果受數(shù)據(jù)規(guī)模影響很大。

大O復(fù)雜度表示法:

例1:

1  int cal(int n) {
2    int sum = 0;
3    int i = 1;
4    for (; i <= n; ++i) {
5     sum = sum + i;
6    }
7    return sum;
8  }

從 CPU 的角度來看,這段代碼的每一行都執(zhí)行著類似的操作:讀數(shù)據(jù)-運(yùn)算-寫數(shù)據(jù)。盡管每行代碼對(duì)應(yīng)的 CPU 執(zhí)行的個(gè)數(shù)、執(zhí)行的時(shí)間都不一樣,但是,我們這里只是粗略估計(jì),所以可以假設(shè)每行代碼執(zhí)行的時(shí)間都一樣,為 unit_time。在這個(gè)假設(shè)的基礎(chǔ)之上,這段代碼的總執(zhí)行時(shí)間是多少呢?

第 2、3 行代碼分別需要 1 個(gè) unit_time 的執(zhí)行時(shí)間,第 4、5 行都運(yùn)行了 n 遍,所以需要 2n*unit_time 的執(zhí)行時(shí)間,所以這段代碼總的執(zhí)行時(shí)間就是 (2n+2)*unit_time??梢钥闯鰜?,所有代碼的執(zhí)行時(shí)間 T(n) 與每行代碼的執(zhí)行次數(shù)成正比。

例2:

1  int cal(int n) {
2    int sum = 0;
3    int i = 1;
4    int j = 1;
5    for (; i <= n; ++i) {
6      j = 1;
7      for (; j <= n; ++j) {
8        sum = sum +  i * j;
9      }
10    }
11  }

第 2、3、4 行代碼,每行都需要 1 個(gè) unit_time 的執(zhí)行時(shí)間,第 5、6 行代碼循環(huán)執(zhí)行了 n 遍,需要 2n * unit_time 的執(zhí)行時(shí)間,第 7、8 行代碼循環(huán)執(zhí)行了 n^2遍,所以需要 2n^2 * unit_time 的執(zhí)行時(shí)間。所以,整段代碼總的執(zhí)行時(shí)間 T(n) = (2n^2+2n+3)*unit_time 。

盡管我們不知道 unit_time 的具體值,但是通過這兩段代碼執(zhí)行時(shí)間的推導(dǎo)過程,我們可以得到一個(gè)非常重要的規(guī)律,那就是,所有代碼的執(zhí)行時(shí)間 T(n) 與每行代碼的執(zhí)行次數(shù) n 成正比

公式:
T(n)=O(f(n))
其中,

  • T(n) 表示代碼執(zhí)行的時(shí)間;
  • n 表示數(shù)據(jù)規(guī)模的大?。?/li>
  • f(n) 表示每行代碼執(zhí)行的次數(shù)總和。
  • O表示代碼的執(zhí)行時(shí)間 T(n) 與 f(n) 表達(dá)式成正比。

例1即T(n) = O(2n+2),例2即 T(n) = O(2n^2+2n+3)。這就是大 O 時(shí)間復(fù)雜度表示法。其并不具體表示代碼真正的執(zhí)行時(shí)間,而是表示代碼執(zhí)行時(shí)間隨數(shù)據(jù)規(guī)模增長的變化趨勢(shì),所以,也叫作漸進(jìn)時(shí)間復(fù)雜度(asymptotic time complexity),簡稱時(shí)間復(fù)雜度。

當(dāng) n --> +∞,公式中的低階、常量、系數(shù)三部分并不左右增長趨勢(shì),所以都可以忽略。我們只需要記錄一個(gè)最大量級(jí)就可以了,就可以記為:T(n) = O(n); T(n) = O(n^2)。

時(shí)間復(fù)雜度分析的三個(gè)方法:

1.只關(guān)注循環(huán)執(zhí)行次數(shù)最多的一段代碼:

大 O 這種復(fù)雜度表示方法只是表示一種變化趨勢(shì)。忽略公式中的常量、低階、系數(shù),只需要記錄一個(gè)最大階的量級(jí)就可以了。所以,分析算法時(shí)間復(fù)雜度的時(shí)候,也只關(guān)注循環(huán)執(zhí)行次數(shù)最多的那一段代碼就可以了。這段核心代碼執(zhí)行次數(shù)的 n 的量級(jí),就是整段要分析代碼的時(shí)間復(fù)雜度。

2.加法法則:總復(fù)雜度等于量級(jí)最大的那段代碼的復(fù)雜度
int cal(int n) {
   int sum_1 = 0;
   int p = 1;
   for (; p < 100; ++p) {
     sum_1 = sum_1 + p;
   }
 
   int sum_2 = 0;
   int q = 1;
   for (; q < n; ++q) {
     sum_2 = sum_2 + q;
   }
 
   int sum_3 = 0;
   int i = 1;
   int j = 1;
   for (; i <= n; ++i) {
     j = 1; 
     for (; j <= n; ++j) {
       sum_3 = sum_3 +  i * j;
     }
   }
 
   return sum_1 + sum_2 + sum_3;
 }

sum_1時(shí)間復(fù)雜度是個(gè)常量,理應(yīng)被忽略,與規(guī)模n無關(guān)。強(qiáng)調(diào)一下,即便這段代碼循環(huán) 10000 次、100000 次,<font color=red>只要是一個(gè)已知的數(shù),跟 n 無關(guān),照樣也是常量級(jí)的執(zhí)行時(shí)間。</font>當(dāng) n 無限大的時(shí)候,就可以忽略。盡管對(duì)代碼的執(zhí)行時(shí)間會(huì)有很大影響,但是回到時(shí)間復(fù)雜度的概念來說,它表示的是一個(gè)算法執(zhí)行效率與數(shù)據(jù)規(guī)模增長的變化趨勢(shì),所以不管常量的執(zhí)行時(shí)間多大,我們都可以忽略掉。因?yàn)樗旧韺?duì)增長趨勢(shì)并沒有影響。

sum_2是O(n),sum_3是O(n2)。綜合這三段代碼的時(shí)間復(fù)雜度,我們?nèi)∑渲凶畲蟮牧考?jí),即O(n2)。
T(n)=T1(n)+T2(n)=max(O(f(n)), O(g(n))) =O(max(f(n), g(n))).

3. 乘法法則:嵌套代碼的復(fù)雜度等于嵌套內(nèi)外代碼復(fù)雜度的乘積

T(n)=T1(n)*T2(n)=O(f(n))*O(g(n))=O(f(n)*g(n))

也就是說,假設(shè) T1(n) = O(n),T2(n) = O(n^2),則 T1(n) * T2(n) = O(n^3)。

int cal(int n) {
   int ret = 0; 
   int i = 1;
   for (; i < n; ++i) {
     ret = ret + f(i);
   } 
 } 
 
 int fun(int n) {
  int sum = 0;
  int i = 1;
  for (; i < n; ++i) {
    sum = sum + i;
  } 
  return sum;
 }

fun()為T1(n) = O(n),而cal()本身有for循環(huán)即T2(n) = O(n)),for循環(huán)中又調(diào)用了fun(),即T(n) = T1(n) * T2(n) = O(n*n) = O(n^2)。

復(fù)雜度分析這個(gè)東西關(guān)鍵在于“熟練”。

常見時(shí)間復(fù)雜度:

遞增順序依次是:

多項(xiàng)式量級(jí):常量階O(1),對(duì)數(shù)階O(logn),線性階O(n),線性對(duì)數(shù)階O(nlogn),K方階O(n^k)

非多項(xiàng)式量級(jí):指數(shù)階O(2^n),階乘階O(n!)

注:非多項(xiàng)式量級(jí)的算法問題叫作NP(Non-Deterministic Polynomial,非確定多項(xiàng)式)問題。當(dāng)數(shù)據(jù)規(guī)模 n 越來越大時(shí),其執(zhí)行時(shí)間會(huì)急劇增加,求解問題的執(zhí)行時(shí)間會(huì)無限增長。所以,非多項(xiàng)式時(shí)間復(fù)雜度的算法其實(shí)是非常低效的算法,理應(yīng)避免。

時(shí)間復(fù)雜度隨著數(shù)據(jù)規(guī)模變化趨勢(shì)圖.png

源自:Big-O Complexity Chart

O(1)

常量級(jí)時(shí)間復(fù)雜度的表示方法,并不是指只執(zhí)行了一行代碼,即便執(zhí)行了三行,也只能是O(1);只要代碼的執(zhí)行時(shí)間不隨 n 的增大而增長,這樣代碼的時(shí)間復(fù)雜度我們都記作 O(1)?;蛘哒f,一般情況下,只要算法中不存在循環(huán)語句、遞歸語句,即使有成千上萬行的代碼,其時(shí)間復(fù)雜度也是Ο(1)。

O(logn)、O(nlogn)

對(duì)數(shù)階 最常見,也是最難分析的一種。

i=1;
 while (i <= n)  {
   i = i * 2;
 }

代碼執(zhí)行次數(shù) 即i<=n截止,i=1,2,4,8,16,32……2k……2x=n;

求解執(zhí)行次數(shù)就是 求解2^x=n中的x;x=log?n,T(n)=O(log?n);

實(shí)際上,不管是以 2 為底、以 3 為底,還是以 10 為底,我們可以把所有對(duì)數(shù)階的時(shí)間復(fù)雜度都記為 O(logn)。為什么呢?

我們知道,對(duì)數(shù)之間是可以互相轉(zhuǎn)換的,log?n 就等于 log?2 * log?n,所以 O(log?n) = O(C * log?n),其中 C=log?2 是一個(gè)常量?;谖覀兦懊娴囊粋€(gè)理論:在采用大 O 標(biāo)記復(fù)雜度的時(shí)候,可以忽略系數(shù),即 O(Cf(n)) = O(f(n))。所以,O(log?n) 就等于 O(log?n)。因此,在對(duì)數(shù)階時(shí)間復(fù)雜度的表示方法里,我們忽略對(duì)數(shù)的“底”,統(tǒng)一表示為 O(logn)。

O(m+n)、O(m*n)
int cal(int m, int n) {
  int sum_1 = 0;
  int i = 1;
  for (; i < m; ++i) {
    sum_1 = sum_1 + i;
  }
 
  int sum_2 = 0;
  int j = 1;
  for (; j < n; ++j) {
    sum_2 = sum_2 + j;
  }
 
  return sum_1 + sum_2;
}

m 和 n 是表示兩個(gè)數(shù)據(jù)規(guī)模。我們無法事先評(píng)估 m 和 n 誰的量級(jí)大,所以我們?cè)诒硎緩?fù)雜度的時(shí)候,就不能簡單地利用加法法則,省略掉其中一個(gè)。所以,上面代碼的時(shí)間復(fù)雜度就是 O(m+n)。

針對(duì)這種情況,原來的加法法則就不正確了,我們需要將加法規(guī)則改為:T1(m) + T2(n) = O(f(m) + g(n))。但是乘法法則繼續(xù)有效:T1(m)*T2(n) = O(f(m) * f(n))。

數(shù)據(jù)結(jié)構(gòu)操作的復(fù)雜性
數(shù)據(jù)結(jié)構(gòu) 連接 查找 插入 刪除
數(shù)組 1 n n n
n n 1 1
隊(duì)列 n n 1 1
鏈表 n n 1 1
哈希表 - n n n
二分查找樹 n n n n
B樹 log(n) log(n) log(n) log(n)
紅黑樹 log(n) log(n) log(n) log(n)
AVL樹 log(n) log(n) log(n) log(n)

數(shù)組排序算法復(fù)雜性:

名稱 最優(yōu) 平均 最壞 內(nèi)存 穩(wěn)定
冒泡排序 n n^2 n^2 1 Yes
插入排序 n n^2 n^2 1 Yes
選擇排序 n^2 n^2 n^2 1 No
堆排序 n log(n) n log(n) n log(n) 1 No
歸并排序 n log(n) n log(n) n log(n) n Yes
快速排序 n log(n) n log(n) n^2 log(n) No
希爾排序 n log(n) 取決于差距序列 n (log(n))^2 1 No

空間復(fù)雜度

時(shí)間復(fù)雜度的全稱是漸進(jìn)時(shí)間復(fù)雜度,表示算法的執(zhí)行時(shí)間與數(shù)據(jù)規(guī)模之間的增長關(guān)系。類比一下,空間復(fù)雜度全稱就是漸進(jìn)空間復(fù)雜度(asymptotic space complexity),表示算法的存儲(chǔ)空間與數(shù)據(jù)規(guī)模之間的增長關(guān)系。1

1 void print(int n) {
2   int i = 0;
3   int[] a = new int[n];
4   for (i; i <n; ++i) {
5     a[i] = i * i;
6   }
 
  for (i = n-1; i >= 0; --i) {
    print out a[i]
  }
 }

第 2 行代碼中,我們申請(qǐng)了一個(gè)空間存儲(chǔ)變量 i,但是它是常量階的,跟數(shù)據(jù)規(guī)模 n 沒有關(guān)系,所以我們可以忽略。第 3 行申請(qǐng)了一個(gè)大小為 n 的 int 類型數(shù)組,除此之外,剩下的代碼都沒有占用更多的空間,所以整段代碼的空間復(fù)雜度就是 O(n)。

我們常見的空間復(fù)雜度就是 O(1)、O(n)、O(n2 ),像 O(logn)、O(nlogn) 這樣的對(duì)數(shù)階復(fù)雜度平時(shí)都用不到。而且,空間復(fù)雜度分析比時(shí)間復(fù)雜度分析要簡單很多。所以,對(duì)于空間復(fù)雜度,掌握這些內(nèi)容已經(jīng)足夠了。

復(fù)雜度分析法則
1)單段代碼看高頻:比如循環(huán)。
2)多段代碼取最大:比如一段代碼中有單循環(huán)和多重循環(huán),那么取多重循環(huán)的復(fù)雜度。
3)嵌套代碼求乘積:比如遞歸、多重循環(huán)等
4)多個(gè)規(guī)模求加法:比如方法有兩個(gè)參數(shù)控制兩個(gè)循環(huán)的次數(shù),那么這時(shí)就取二者復(fù)雜度相加。

一、復(fù)雜度分析的4個(gè)概念:

  • 1.最壞情況時(shí)間復(fù)雜度:代碼在最理想情況下執(zhí)行的時(shí)間復(fù)雜度。

  • 2.最好情況時(shí)間復(fù)雜度:代碼在最壞情況下執(zhí)行的時(shí)間復(fù)雜度。

  • 3.平均時(shí)間復(fù)雜度:用代碼在所有情況下執(zhí)行的次數(shù)的加權(quán)平均值表示。

  • 4.均攤時(shí)間復(fù)雜度:在代碼執(zhí)行的所有復(fù)雜度情況中絕大部分是低級(jí)別的復(fù)雜度,個(gè)別情況是高級(jí)別復(fù)雜度且發(fā)生具有時(shí)序關(guān)系時(shí),可以將個(gè)別高級(jí)別復(fù)雜度均攤到低級(jí)別復(fù)雜度上。基本上均攤結(jié)果就等于低級(jí)別復(fù)雜度。

    分別解釋四種情況:

    長度為n的數(shù)組中查找x的下標(biāo),來返回,找不到則返回-1;

    // n 表示數(shù)組 array 的長度
    int find(int[] array, int n, int x) {
      int i = 0;
      int pos = -1;
      for (; i < n; ++i) {
        if (array[i] == x) {
           pos = i;
           //break;//TODO:找到即跳出
        }
      }
      return pos;
    }
    

    1.如果不加break的話,O(n)

    2.加上break后,或許array[0]就是x,復(fù)雜度O(1)【最好情況】,只有數(shù)組不包含x時(shí),才循環(huán)到n次【最差情況】。

    最好情況 和 最壞情況 都是極端情況。引入一個(gè)概念:平均時(shí)間復(fù)雜度。

    要查找的變量 x 在數(shù)組中的位置,有 n+1 種情況:在數(shù)組的 0~n-1 位置中不在數(shù)組中。我們把每種情況下,查找需要遍歷的元素個(gè)數(shù)累加起來,然后再除以 n+1,就可以得到需要遍歷的元素個(gè)數(shù)的平均值,即:
    \frac {1+2+3+……+n+n}{n+1}=\frac{n(n+3)}{2(n+1)}
    省略掉系數(shù)、低階、常量,簡化之后,得到的平均時(shí)間復(fù)雜度就是 O(n)。

    這個(gè)結(jié)論雖然是正確的,但是計(jì)算過程稍微有點(diǎn)兒問題。究竟是什么問題呢?我們剛講的這 n+1 種情況,出現(xiàn)的概率并不是一樣的。

    我們知道,要查找的變量 x,要么在數(shù)組里,要么就不在數(shù)組里。這兩種情況對(duì)應(yīng)的概率統(tǒng)計(jì)起來很麻煩,為了方便你理解,我們假設(shè)在數(shù)組中與不在數(shù)組中的概率都為 1/2。另外,要查找的數(shù)據(jù)出現(xiàn)在 0~n-1 這 n 個(gè)位置的概率也是一樣的,為 1/n。所以,根據(jù)概率乘法法則,要查找的數(shù)據(jù)出現(xiàn)在 0~n-1 中任意位置的概率就是 1/(2n)。

    因此,前面的推導(dǎo)過程中存在的最大問題就是,沒有將各種情況發(fā)生的概率考慮進(jìn)去。如果我們把每種情況發(fā)生的概率也考慮進(jìn)去,那平均時(shí)間復(fù)雜度的計(jì)算過程就變成了這樣:
    1*\frac{1}{2n}+2*\frac{1}{2n}+3*\frac{1}{2n}+…+n*\frac{1}{2n}+n*\frac{1}{2}=\frac{3n+1}{4}
    這個(gè)值就是概率論中的加權(quán)平均值,也叫作期望值,所以平均時(shí)間復(fù)雜度的全稱應(yīng)該叫加權(quán)平均時(shí)間復(fù)雜度或者期望時(shí)間復(fù)雜度。

    去掉系數(shù)和常量,這段代碼的加權(quán)平均時(shí)間復(fù)雜度仍然是 O(n)。

    在大多數(shù)情況下,我們并不需要區(qū)分最好、最壞、平均情況時(shí)間復(fù)雜度三種情況。很多時(shí)候,我們使用一個(gè)復(fù)雜度就可以滿足需求了。只有同一塊代碼在不同的情況下,時(shí)間復(fù)雜度有量級(jí)的差距,我們才會(huì)使用這三種復(fù)雜度表示法來區(qū)分。

    均攤時(shí)間復(fù)雜度

    平均復(fù)雜度只在某些特殊情況下才會(huì)用到,而均攤時(shí)間復(fù)雜度應(yīng)用的場(chǎng)景比它更加特殊、更加有限。

     // array 表示一個(gè)長度為 n 的數(shù)組
     // 代碼中的 array.length 就等于 n
     int[] array = new int[n];
     int count = 0;
     
     void insert(int val) {
        if (count == array.length) {
           int sum = 0;
           for (int i = 0; i < array.length; ++i) {
              sum = sum + array[i];
           }
           array[0] = sum;
           count = 1;
        }
     
        array[count] = val;
        ++count;
     }
    
    

    這段代碼實(shí)現(xiàn)了一個(gè)往數(shù)組中插入數(shù)據(jù)的功能。當(dāng)數(shù)組滿了之后,也就是代碼中的 count == array.length 時(shí),我們用 for 循環(huán)遍歷數(shù)組求和,并清空數(shù)組,將求和之后的 sum 值放到數(shù)組的第一個(gè)位置,然后再將新的數(shù)據(jù)插入。但如果數(shù)組一開始就有空閑空間,則直接將數(shù)據(jù)插入數(shù)組。

    最好為O(1),最差為O(n)。

    那平均時(shí)間復(fù)雜度是多少呢?答案是 O(1)。我們還是可以通過前面講的概率論的方法來分析。

    假設(shè)數(shù)組的長度是 n,根據(jù)數(shù)據(jù)插入的位置的不同,我們可以分為 n 種情況,每種情況的時(shí)間復(fù)雜度是 O(1)。除此之外,還有一種“額外”的情況,就是在數(shù)組沒有空閑空間時(shí)插入一個(gè)數(shù)據(jù),這個(gè)時(shí)候的時(shí)間復(fù)雜度是 O(n)。而且,這 n+1 種情況發(fā)生的概率一樣,都是 1/(n+1)。所以,根據(jù)加權(quán)平均的計(jì)算方法,我們求得的平均時(shí)間復(fù)雜度就是:
    1*\frac{1}{n+1}+1*\frac{1}{n+1}+…+1*\frac{1}{n+1}+…+1*\frac{1}{n+1}+n*\frac{1}{n+1}=O(1)

其實(shí)理解平均復(fù)雜度不需這么復(fù)雜,我們可以對(duì)比 insert() 和find()的區(qū)別:

1.find() 只有在極端情況下,才為 O(1)。但 insert() 通常為 O(1),極端情況下O(n)。

2.insert() 中O(1) 和 O(n) 出現(xiàn)的頻率有規(guī)律,且有一定的前后時(shí)序關(guān)系,一個(gè) O(n)之后,緊跟著 n-1 個(gè) O(1) ,周期循環(huán)。

針對(duì)這種特殊的場(chǎng)景,完全不需要平均復(fù)雜度那樣用概率加權(quán)平均,我們引入了一種更加簡單的分析方法:攤還分析法,對(duì)應(yīng)均攤時(shí)間復(fù)雜度。

如何用?每一個(gè)O(n) 緊跟 n-1 個(gè) O(1) ,把耗時(shí)多的那次操作均攤到接下來的 n-1 次耗時(shí)少的操作上,均攤下來,這一組連續(xù)的操作的均攤時(shí)間復(fù)雜度就是 O(1)。這就是均攤分析的大致思路。該方法不常用,點(diǎn)到為止。

簡單總結(jié)下:對(duì)一個(gè)數(shù)據(jù)結(jié)構(gòu)進(jìn)行一組連續(xù)操作中,大部分情況下時(shí)間復(fù)雜度都很低,只有個(gè)別情況下時(shí)間復(fù)雜度比較高,而且這些操作之間存在前后連貫的時(shí)序關(guān)系,這個(gè)時(shí)候,我們就可以將這一組操作放在一塊兒分析,看是否能將較高時(shí)間復(fù)雜度那次操作的耗時(shí),平攤到其他那些時(shí)間復(fù)雜度比較低的操作上。而且,在能夠應(yīng)用均攤時(shí)間復(fù)雜度分析的場(chǎng)合,一般均攤時(shí)間復(fù)雜度就等于最好情況時(shí)間復(fù)雜度。

二、為什么要引入這4個(gè)概念?

1.同一段代碼在不同情況下時(shí)間復(fù)雜度會(huì)出現(xiàn)量級(jí)差異,為了更全面,更準(zhǔn)確的描述代碼的時(shí)間復(fù)雜度,所以引入這4個(gè)概念。

2.代碼復(fù)雜度在不同情況下出現(xiàn)量級(jí)差別時(shí)才需要區(qū)別這四種復(fù)雜度。大多數(shù)情況下,是不需要區(qū)別分析它們的。

三、如何分析平均、均攤時(shí)間復(fù)雜度?

1.平均時(shí)間復(fù)雜度

代碼在不同情況下復(fù)雜度出現(xiàn)量級(jí)差別,則用代碼所有可能情況下執(zhí)行次數(shù)的加權(quán)平均值表示。

2.均攤時(shí)間復(fù)雜度

兩個(gè)條件滿足時(shí)使用:1)代碼在絕大多數(shù)情況下是低級(jí)別復(fù)雜度,只有極少數(shù)情況是高級(jí)別復(fù)雜度;2)低級(jí)別和高級(jí)別復(fù)雜度出現(xiàn)具有時(shí)序規(guī)律。均攤結(jié)果一般都等于低級(jí)別復(fù)雜度。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容