1. 程式人生 > >iOS面試題:阿里-P6一面

iOS面試題:阿里-P6一面

阿里-p6-一面

  • 1.介紹下記憶體的幾大區域?

  • 2.你是如何元件化解耦的?

  • 3.runtime如何通過selector找到對應的IMP地址

  • 4.runloop內部實現邏輯?

  • 5.你理解的多執行緒?

  • 6.GCD執行原理?

  • 7.怎麼防止別人反編譯你的app?

  • 8.YYAsyncLayer如何非同步繪製?

  • 9.優化你是從哪幾方面著手?

1.介紹下記憶體的幾大區域?

1.棧區(stack) 由編譯器自動分配並釋放,存放函式的引數值,區域性變數等。棧是系統資料結構,對應執行緒/程序是唯一的。優點是快速高效,缺點時有限制,資料不靈活。[先進後出]

棧空間分靜態分配 和動態分配兩種。

1.jpg

堆區(heap) 由程式設計師分配和釋放,如果程式設計師不釋放,程式結束時,可能會由作業系統回收 ,比如在ios 中 alloc 都是存放在堆中。

優點是靈活方便,資料適應面廣泛,但是效率有一定降低。

2.png

雖然程式結束時所有的資料空間都會被釋放回系統,但是精確的申請記憶體,釋放記憶體匹配是良好程式的基本要素。

3.全域性區(靜態區) (static) 全域性變數和靜態變數的儲存是放在一起的,初始化的全域性變數和靜態變數存放在一塊區域,未初始化的全域性變數和靜態變數在相鄰的另一塊區域,程式結束後有系統釋放。

3.jpg

4.文字常量區 存放常量字串,程式結束後由系統釋放;

5.程式碼區 存放函式的二進位制程式碼

大致如圖:

4.jpg

5.jpg

例子程式碼:

6.jpg

可能被追問的問題一:

1.棧區 (stack [stæk]): 由編譯器自動分配釋放

區域性變數是儲存在棧區的

方法呼叫的實參也是儲存在棧區的

2.堆區 (heap [hiːp]): 由程式設計師分配釋放,若程式設計師不釋放,會出現記憶體洩漏,賦值語句右側 使用 new 方法建立的物件,被建立物件的所有 成員變數!

3.BSS 段 : 程式結束後由系統釋放

4.資料段 : 程式結束後由系統釋放

5.程式碼段:程式結束後由系統釋放

程式編譯連結 後的二進位制可執行程式碼

可能被追問的問題二:

比如申請後的系統是如何響應的?

棧:儲存每一個函式在執行的時候都會向作業系統索要資源,棧區就是函式執行時的記憶體,棧區中的變數由編譯器負責分配和釋放,記憶體隨著函式的執行分配,隨著函式的結束而釋放,由系統自動完成。

注意:只要棧的剩餘空間大於所申請空間,系統將為程式提供記憶體,否則將報異常提示棧溢位。

堆:

1.首先應該知道作業系統有一個記錄空閒記憶體地址的連結串列。

2.當系統收到程式的申請時,會遍歷該連結串列,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點連結串列中刪除,並將該結點的空間分配給程式。

3 .由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒連結串列中

可能被追問的問題三:

比如:申請大小的限制是怎樣的?

棧:棧是向低地址擴充套件的資料結構,是一塊連續的記憶體的區域。是棧頂的地址和棧的最大容量是系統預先規定好的,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數 ) ,如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。

堆:堆是向高地址擴充套件的資料結構,是不連續的記憶體區域。這是由於系統是用連結串列來儲存的空閒記憶體地址的,自然是不連續的,而連結串列的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬記憶體。由此可見,堆獲得的空間比較靈活,也比較大。

1829339-e2f4c6c2173545a8.png

棧:由系統自動分配,速度較快,不會產生記憶體碎片

堆:是由alloc分配的記憶體,速度比較慢,而且容易產生記憶體碎片,不過用起來最方便

打個比喻來說:

使用棧就象我們去飯館裡吃飯,只管點菜(發出申請)、付錢、和吃(使用),吃飽了就走,不必理會切菜、洗菜等準備工作和洗碗、刷鍋等掃尾工作,他的好處是快捷,但是自由度小。

使用堆就象是自己動手做喜歡吃的菜餚,比較麻煩,但是比較符合自己的口味,而且自由度大。

2.你是如何元件化解耦的?

實現程式碼的高內聚低耦合,方便多人多團隊開發!

一般需要解耦的專案都會多多少少出現,一下幾個情況:

耦合比較嚴重(因為沒有明確的約束,「元件」間引用的現象會比較多)

2.容易出現衝突(尤其是使用 Xib,還有就是 Xcode Project,雖說有指令碼可以改善)

3.業務方的開發效率不夠高(只關心自己的元件,卻要編譯整個專案,與其他不相干的程式碼糅合在一起)

先來看下,元件化之後的一個大概架構

1829339-72fb5f50c9b2865c.jpg

「元件化」顧名思義就是把一個大的 App 拆成一個個小的元件,相互之間不直接引用。那如何做呢?

元件間通訊

以 iOS 為例,由於之前就是採用的 URL 跳轉模式,理論上頁面之間的跳轉只需 open 一個 URL 即可。所以對於一個元件來說,只要定義「支援哪些 URL」即可,比如詳情頁,大概可以這麼做的

1829339-11ffcf987053253a.jpg

首頁只需呼叫[MGJRouter openURL:@"mgj://detail?id=404"]就可以開啟相應的詳情頁。

那問題又來了,我怎麼知道有哪些可用的 URL?為此,我們做了一個後臺專門來管理。

1829339-594af78f0a11738b.jpg

然後可以把這些短鏈生成不同平臺所需的檔案,iOS 平臺生成 .{h,m} 檔案,Android 平臺生成 .java 檔案,並注入到專案中。這樣開發人員只需在專案中開啟該檔案就知道所有的可用 URL 了。

目前還有一塊沒有做,就是引數這塊,雖然描述了短鏈,但真想要生成完整的 URL,還需要知道如何傳引數,這個正在開發中。

還有一種情況會稍微麻煩點,就是「元件A」要呼叫「元件B」的某個方法,比如在商品詳情頁要展示購物車的商品數量,就涉及到向購物車元件拿資料。

類似這種同步呼叫,iOS 之前採用了比較簡單的方案,還是依託於MGJRouter,不過添加了新的方法- (id)objectForURL:,註冊時也使用新的方法進行註冊

1829339-f6ecd4ca2e4c3c4a.jpg

使用時NSNumber *orderCount = [MGJRouter objectForURL:@"mgj://cart/ordercount"]這樣就拿到了購物車裡的商品數。

稍微複雜但更具通用性的方法是使用「協議」 <-> 「類」繫結的方式,還是以購物車為例,購物車元件可以提供這麼個 Protocol

1829339-234e7e6ad55f0b6c.png

可以看到通過協議可以直接指定返回的資料型別。然後在購物車元件內再新建個類實現這個協議,假設這個類名為MGJCartImpl,接著就可以把它與協議關聯起來[ModuleManagerregisterClass:MGJCartImplforProtocol:@protocol(MGJCart)],對於使用方來說,要拿到這個MGJCartImpl,需要呼叫[ModuleManagerclassForProtocol:@protocol(MGJCart)]。拿到之後再呼叫+ (NSInteger)orderCount就可以了。

那麼,這個協議放在哪裡比較合適呢?如果跟元件放在一起,使用時還是要先引入元件,如果有多個這樣的元件就會比較麻煩了。所以我們把這些公共的協議統一放到了PublicProtocolDomain.h下,到時只依賴這一個檔案就可以了。

Android 也是採用類似的方式。

元件生命週期管理

理想中的元件可以很方便地整合到主客中,並且有跟AppDelegate一致的回撥方法。這也是ModuleManager做的事情。

先來看看現在的入口方法

1829339-0ed8e31502ef75ea.jpg

其中[MGJApp startApp]主要負責一些 SDK 的初始化。[self trackLaunchTime]是我們打的一個點,用來監測從main方法開始到入口方法呼叫結束花了多長時間。其他的都由ModuleManager搞定,loadModuleFromPlist:pathForResource:方法會讀取 bundle 裡的一個 plist 檔案,這個檔案的內容大概是這樣的

1829339-6caba6cac1f75639.jpg

每個Module都實現了ModuleProtocol,其中有一個- (BOOL)applicaiton:didFinishLaunchingWithOptions:方法,如果實現了的話,就會被呼叫。

還有一個問題就是,系統的一些事件會有通知,比如applicationDidBecomeActive會有對應的UIApplicationDidBecomeActiveNotification,元件如果要做響應的話,只需監聽這個系統通知即可。但也有一些事件是沒有通知的,比如- application:didRegisterUserNotificationSettings:,這時元件如果也要做點事情,怎麼辦?

一個簡單的解決方法是在AppDelegate的各個方法裡,手動調一遍元件的對應的方法,如果有就執行。

1829339-469b0ffd864a57bc.jpg

殼工程

既然已經拆出去了,那拆出去的元件總得有個載體,這個載體就是殼工程,殼工程主要包含一些基礎元件和業務SDK,這也是主工程包含的一些內容,所以如果在殼工程可以正常執行的話,到了主工程也沒什麼問題。不過這裡存在版本同步問題,之後會說到。

遇到的問題

元件拆分

由於之前的程式碼都是在一個工程下的,所以要單獨拿出來作為一個元件就會遇到不少問題。首先是元件的劃分,當時在定義元件粒度時也花了些時間討論,究竟是粒度粗點好,還是細點好。粗點的話比較有利於拆分,細點的話靈活度比較高。最終還是選擇粗一點的粒度,先拆出來再說。

假如要把詳情頁遷出來,就會發現它依賴了一些其他部分的程式碼,那最快的方式就是直接把程式碼拷過來,改個名使用。比較簡單暴力。說起來比較簡單,做的時候也是挺有挑戰的,因為正常的業務並不會因為「元件化」而停止,所以開發同學們需要同時兼顧正常的業務和元件的拆分。

版本管理

我們的元件包括第三方庫都是通過 Cocoapods 來管理的,其中元件使用了私有庫。之所以選擇 Cocoapods,一個是因為它比較方便,還有就是使用者基數比較大,且社群也比較活躍(活躍到了會時不時地觸發 Github 的 rate limit,導致長時間 clone 不下來···見此),當然也有其他的管理方式,比如 submodule / subtree,在開發人員比較多的情況下,方便、靈活的方案容易佔上風,雖然它也有自己的問題。主要有版本同步和更新/編譯慢的問題。

假如基礎元件做了個 API 介面升級,這個升級會對原有的介面做改動,自然就會升一箇中位的版本號,比如原先是 1.6.19,那麼現在就變成 1.7.0 了。而我們在 Podfile 裡都是用~指定的,這樣就會出現主工程的 pod 版本升上去了,但是殼工程沒有同步到,然後群裡就會各種反饋編譯不過,而且這個編譯不過的長尾有時能拖上兩三天。

然後我們就想了個辦法,如果不在殼工程裡指定基礎庫的版本,只在主工程裡指定呢,理論上應該可行,只要不出現某個基礎庫要同時維護多個版本的情況。但實踐中發現,殼工程有時會莫名其妙地升不上去,在 podfile 裡指定最新的版本又可以升上去,所以此路不通。

還有一個問題是pod update時間過長,經常會在Analyzing Dependency上卡 10 多分鐘,非常影響效率。後來排查下來是跟元件的 Podspec 有關,配置了 subspec,且依賴比較多。

然後就是 pod update 之後的編譯,由於是原始碼編譯,所以這塊的時間花費也不少,接下去會考慮 framework 的方式。

持續整合

在剛開始,持續整合還不是很完善,業務方升級元件,直接把 podspec 扔到 private repo 裡就完事了。這樣最簡單,但也經常會帶來編譯通不過的問題。而且這種隨意的版本升級也不太能保證質量。於是我們就搭建了一套持續整合系統,大概如此

1829339-ac6032723d385319.jpg

每個元件升級之前都需要先通過編譯,然後再決定是否升級。這套體系看起來不復雜,但在實施過程中經常會遇到後端的併發問題,導致業務方要麼整合失敗,要麼要等不少時間。而且也沒有一個地方可以呈現當前版本的元件版本資訊。還有就是業務方對於這種命令列的升級方式接受度也不是很高。

1829339-b69baa9839f44ca9.jpg

基於此,在經過了幾輪討論之後,有了新版的持續整合平臺,升級操作通過網頁端來完成。

大致思路是,業務方如果要升級元件,假設現在的版本是 0.1.7,添加了一些 feature 之後,殼工程測試通過,想整合到主工程裡看看效果,或者其他元件也想引用這個最新的,就可以在後臺手動把版本升到 0.1.8-rc.1,這樣的話,原先依賴~> 0.1.7的元件,不會升到 0.1.8,同時想要測試這個元件的話,只要手動把版本調到 0.1.8-rc.1 就可以了。這個過程不會觸發 CI 的編譯檢查。

當測試通過後,就可以把尾部的-rc.n去掉,然後點選「整合」,就會走 CI 編譯檢查,通過的話,會在主工程的 podfile 裡寫上固定的版本號 0.1.8。也就是說,podfile 裡所有的元件版本號都是固定的。

1829339-ef59bd8d0d9316b9.jpg

周邊設施

基礎元件及元件的文件 / Demo / 單元測試

無線基礎的職能是為集團提供解決方案,只是在蘑菇街 App 裡能 work 是遠遠不夠的,所以就需要提供入口,知道有哪些可用元件,並且如何使用,就像這樣(目前還未實現)

1829339-3c35eff9ddcc89eb.jpg

這就要求元件的負責人需要及時地更新 README / CHANGELOG / API,並且當發生 API 變更時,能夠快速通知到使用方。

公共 UI 元件

元件化之後還有一個問題就是資源的重複性,以前在一個工程裡的時候,資源都可以很方便地拿到,現在獨立出去了,也不知道哪些是公用的,哪些是獨有的,索性都放到自己的元件裡,這樣就會導致包變大。還有一個問題是每個元件可能是不同的產品經理在跟,而他們很可能只關注於自己關心的頁面長什麼樣,而忽略了整體的樣式。公共

UI 元件就是用來解決這些問題的,這些元件甚至可以跨 App 使用。(目前還未實現)

1829339-b9b1b24062ce3dc0.jpg

參考答案一:http://blog.csdn.net/GGGHub/article/details/52713642

參考答案二:http://limboy.me/tech/2016/03/10/mgj-components.html

3.runtime如何通過selector找到對應的IMP地址?

概述

類物件中有類方法和例項方法的列表,列表中記錄著方法的名詞、引數和實現,而selector本質就是方法名稱,runtime通過這個方法名稱就可以在列表中找到該方法對應的實現。

這裡聲明瞭一個指向struct objc_method_list指標的指標,可以包含類方法列表和例項方法列表

具體實現

在尋找IMP的地址時,runtime提供了兩種方法

IMP class_getMethodImplementation(Class cls, SEL name);IMP method_getImplementation(Method m)

而根據官方描述,第一種方法可能會更快一些

@note \c class_getMethodImplementation may be faster than \c method_getImplementation(class_getInstanceMethod(cls, name)).

對於第一種方法而言,類方法和例項方法實際上都是通過呼叫class_getMethodImplementation()來尋找IMP地址的,不同之處在於傳入的第一個引數不同

類方法(假設有一個類A)

class_getMethodImplementation(objc_getMetaClass("A"),@selector(methodName));

例項方法

class_getMethodImplementation([A class],@selector(methodName));

通過該傳入的引數不同,找到不同的方法列表,方法列表中儲存著下面方法的結構體,結構體中包含這方法的實現,selector本質就是方法的名稱,通過該方法名稱,即可在結構體中找到相應的實現。

struct objc_method {SEL method_namechar *method_typesIMP method_imp}

而對於第二種方法而言,傳入的引數只有method,區分類方法和例項方法在於封裝method的函式

類方法

Method class_getClassMethod(Class cls, SEL name)

例項方法

Method class_getInstanceMethod(Class cls, SEL name)

最後呼叫IMP method_getImplementation(Method m)獲取IMP地址

實驗

1829339-3b759827c7c1bd46.jpg

這裡有一個叫Test的類,在初始化方法裡,呼叫了兩次getIMPFromSelector:方法,第一個aaa方法是不存在的,test1和test2分別為例項方法和類方法

1829339-2993344a6a931f8c.png

然後我同時例項化了兩個Test的物件,列印資訊如下

1829339-4a5991505e1848b0.jpg

大家注意圖中紅色標註的地址出現了8次:0x1102db280,這個是在呼叫class_getMethodImplementation()方法時,無法找到對應實現時返回的相同的一個地址,無論該方法是在例項方法或類方法,無論是否對一個例項呼叫該方法,返回的地址都是相同的,但是每次執行該程式時返回的地址並不相同,而對於另一種方法,如果找不到對應的實現,則返回0,在圖中我做了藍色標記。

還有一點有趣的是class_getClassMethod()的第一個引數無論傳入objc_getClass()還是objc_getMetaClass(),最終呼叫method_getImplementation()都可以成功的找到類方法的實現。

而class_getInstanceMethod()的第一個引數如果傳入objc_getMetaClass(),再呼叫method_getImplementation()時無法找到例項方法的實現卻可以找到類方法的實現。

4.runloop內部實現邏輯?

1829339-2b34e3eede12d705.jpg

蘋果在文件裡的說明,RunLoop 內部的邏輯大致如下:

1829339-d378878ffdf4c6ae.jpg

其內部程式碼整理如下 :

可以看到,實際上 RunLoop 就是這樣一個函式,其內部是一個 do-while 迴圈。當你呼叫 CFRunLoopRun() 時,執行緒就會一直停留在這個迴圈裡;直到超時或被手動停止,該函式才會返回。

RunLoop 的底層實現

從上面程式碼可以看到,RunLoop 的核心是基於 mach port 的,其進入休眠時呼叫的函式是 mach_msg()。為了解釋這個邏輯,下面稍微介紹一下 OSX/iOS 的系統架構。

1829339-be19d014752b22c0.png

蘋果官方將整個系統大致劃分為上述4個層次:

應用層包括使用者能接觸到的圖形應用,例如 Spotlight、Aqua、SpringBoard 等。

應用框架層即開發人員接觸到的 Cocoa 等框架。

核心框架層包括各種核心框架、OpenGL 等內容。

Darwin 即作業系統的核心,包括系統核心、驅動、Shell 等內容,這一層是開源的,其所有原始碼都可以在opensource.apple.com裡找到。

我們在深入看一下 Darwin 這個核心的架構:

1829339-a9bd8e6efe4245a6.png

其中,在硬體層上面的三個組成部分:Mach、BSD、IOKit (還包括一些上面沒標註的內容),共同組成了 XNU 核心。

XNU 核心的內環被稱作 Mach,其作為一個微核心,僅提供了諸如處理器排程、IPC (程序間通訊)等非常少量的基礎服務。

BSD 層可以看作圍繞 Mach 層的一個外環,其提供了諸如程序管理、檔案系統和網路等功能。

IOKit 層是為裝置驅動提供了一個面向物件(C++)的一個框架。

Mach

本身提供的 API 非常有限,而且蘋果也不鼓勵使用 Mach 的

API,但是這些API非常基礎,如果沒有這些API的話,其他任何工作都無法實施。在 Mach

中,所有的東西都是通過自己的物件實現的,程序、執行緒和虛擬記憶體都被稱為"物件"。和其他架構不同, Mach

的物件間不能直接呼叫,只能通過訊息傳遞的方式實現物件間的通訊。"訊息"是 Mach 中最基礎的概念,訊息在兩個埠 (port)

之間傳遞,這就是 Mach 的 IPC (程序間通訊) 的核心。

Mach 的訊息定義是在標頭檔案的,很簡單:

12

相關推薦

iOS試題阿里-P6一面

阿里-p6-一面1.介紹下記憶體的幾大區域?2.你是如何元件化解耦的?3.runtime如何通過selector找到對應的IMP地址4.runloop內部實現邏輯?5.你理解的多執行緒?6.GCD執行原理?7.怎麼防止別人反編譯你的app?8.YYAsyncLayer如何非同

Java程式設計師最全技術試題阿里11面試+百度+美團

網路程式設計 文末有答案解析以及阿里架構師精講視訊資料。 ISO模型與協議 http1.0:需要使用keep-alive引數來告知伺服器端要建立一個長連線 http1.1:預設長連線。支援只發送header資訊,可以用作許可權請求。支援Host域。

阿里試題FileInputStream 在使用完以後,不關閉流,想二次使用可以怎麼操作

FileInputStream 中有一個方法是open 方法呼叫的是本地的開啟檔案的方法,fileinputStream 就是通過這個方法來開啟檔案的,所以如果要重寫讀取這個檔案,不重新建立物件,那麼只要呼叫這個方法就可以了。 /** * Opens the specifie

阿里巴巴試題 為什麼wait()和notify()需要搭配synchonized關鍵字使用

本文主要參考 理解此問題先修知識: synchronized 的含義: Java中每一個物件都可以成為一個監視器(Monitor), 該Monitor由一個鎖(lock), 一個

iOS 試題(1)一個 Objective-C 物件的記憶體結構是怎樣的?

接下來分享的將會是唐老師一系列的iOS面試題,因為之前好幾期唐老師都刪掉了,說是要出書,所以轉載過來,需要的朋友們可以看下,也方便我自己鞏固、學習。 轉載自:http://mp.weixin.qq.com/s?__biz=MjM5NTIyNTUyMQ==&mid=

金三銀四螞蟻金服JAVA開發試題及答案之一面(持續更新)

開發十年,就只剩下這套架構體系了! >>>   

49. 搜狗試題 大數相乘算法

std margin -a pac string out none content ack 分析: 大數能大到整形類型存儲不了。須要借助於其它的算法,來完畢乘法運算。 能夠使用口算乘法的步驟來模擬乘法操作。例如以下:

Java(試題)字符串截取

int lan out 試題 void trace 題目 replace odi 在Java中,字符串“abcd”與字符串“ab你好”的長度是一樣,都是四個字符。 但對應的字節數不同,一個漢字占兩個字節。 定義一個方法,按照指定的字節數來取子串。 如:對於“ab你好”,如果

18、iOS試題·自整理·One

新特性 服務器端 ssd 關閉 綁架 利好 pla ken 技巧 ◆如何解決低內存問題? ForExample:將暫時沒有展示在Window中的界面銷毀,以獲得足夠的內存; ◆POST請求的數據類型有哪些? json、xml、二進制、參數拼接; ◆請簡述你理解的面向對

19、iOS試題·自整理·Three

-c 得到 設計 ica oschina 參數 dexp 不能 整理 p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: justify; text-indent: 21.0px; font: 10.5px "Songti

試題軟件測試,如何測微信的朋友圈?

功能 此外 nal testing 測試 常用 tar pad 軟件 任何一個東西你都可以這麽測:記住sfdipot: s,structure,結構。考慮其組成部分,微信朋友圈的代碼組成,客戶端是怎麽樣的,服務端是怎麽樣的。 f,function,功能。考慮單個功

試題HTTP與HTTPS

模型 開頭 tro 工作 ron 傳輸層 進行 證書 str 記錄個面試題 HTTP與HTTPS的不同 1.HTTP的URL為http://開頭,HTTPS的URL為https://開頭 2.HTTP標準端口80,HTTPS標準端口是443 3.在OSI網絡模型中,HTTP

經典試題js繼承方式下

deep 今天 typeof extend fun col const 繼承 uber 上一篇講解了構造函數的繼承方式,今天來講非構造函數的繼承模式。 一、object()方法 json格式的發明人Douglas Crockford,提出了一個object()函數,可以做到

Java 試題百度前200頁都在這裏了

serializa 負載 第三方 lin 目的 safe 並排 原理 java虛擬機 基本概念 操作系統中 heap 和 stack 的區別 什麽是基於註解的切面實現 什麽是 對象/關系 映射集成模塊 什麽是 Java 的反射機制 什麽是 ACID BS與CS的聯系與區別

java基礎試題switch語句能否作用在byte上,能否作用在long上,能否作用在String上?

int 包裝類 println class ava col body package 面試題 package com.swift; public class Switch_Test { public static void main(String[] args

java基礎試題try{}裏有一個return語句,那麽緊跟在這個try後的finally {}裏的code會不會被執行,什麽時候被執行,在return前還是後?

nal java pan clas out bsp 出現 可能 inf package com.swift; public class Try_Catch_Finally_Test { public static void main(String[] args

java算法試題排序都有哪幾種方法?請列舉。用JAVA實現一個快速排序。選擇冒泡快速集合至少4種方法排序

算法 err div println rda print 算法面試 ++ 快速排序 package com.swift; import java.util.ArrayList; import java.util.Collections; import java.util

java算法試題遞歸算法題2 第1個人10,第2個比第1個人大2歲,依次遞推,請用遞歸方式計算出第8個人多大?

else oid 算法題 body println 算法 ring swift java算法 package com.swift; public class Digui_Return { public static void main(String[] arg