在做關於數組的算法題之前,一定要先對數組有一定的了解: C#中的數組一旦被創建,大小就固定了,且不支持動態數組。數組的索引是從0開始的,也就是說,一個長度為n的數組,索引為0~(n-1)。
數組實例是從System.Array繼承的對象,數組是引用類型,有數據的引用及數據對象本身,引用在棧或堆上,且數組本身總是在堆上。
數組是引用類型,但數組的元素可以是值類型或引用類型,如果存儲在數組中的元素都是值類型,則數組被稱為值類型數組。如果存儲在數組中的元素都是引用類型對象,數組則被稱為引用類型數組。
合並數組的算法一般分為兩種,一種是兩個有序數組的合並,合並完后保證數組依然有序,還有一種是兩個數組合並並對合並的數組進行排序。
毫無疑問,第二種算法比較簡單,但是,很多人會將第一種情況的處理也同樣使用第二種情況的算法,這不能說是錯誤,但,算法的效率卻大大的降低了,為什么?本來兩個數組都是有序的,一合並,原本有序的有利條件被打破了。那么,應該怎么做才能保證有利條件對我們有幫助呢?下面將兩個算法分開闡述。
先說第二種情況吧,本身數組就是無序的,但合並后要保證數組有序,怎么做?最簡單的思維,反正源數組也是無序的,那么干脆直接合並兩個數組,再對新數組進行一個排序。
先說合並數組吧,定義一個新數組,長度為兩個數組(arr1, arr2)的長度之和,再定義新數組的索引,然后使用兩個for循環即可完成:
排序的算法有很多的選擇,最簡單的冒泡,插入,選擇……這里給出冒泡和插入的算法實現,排序原理不贅述了,不了解的通過各種渠道去找尋答案吧~
也就是說,只需要在代碼里再調用相應的排序算法即可,全部代碼如下:
使用了兩個for循環將兩個數組合並稱為一個新數組,時間復雜度為O(N), 而無論是冒泡還是插入排序,平均的時間復雜度都是O(N*N), 因此,這種情況下算法的時間復雜度為O(N*N).
說完無序數組的合並且排序之后,回到第一種情況,兩個有序數組的排序進行合並,且保證合並后的數組依然有序,前面說過了,如果使用第二種情況的解決方法當然沒問題,但是時間復雜度是O(N*N), 從算法效率上來說,並非最佳算法,而與此同時,我們忽略了題目給到我們的有利條件:數組本身是有序的。
這個有利的條件如何利用,才能讓算法效率更高呢?同樣的,我們需要定義一個新數組來存儲兩個數組合並后的結果,如何插入元素是我們需要動腦筋的,有沒有一個辦法,讓兩個數組中的數據從小到大插入新數組呢?當然有辦法。
取出數組A的第一個元素和數組B的第一個元素,比較,如果A[0]<B[0], 則,A[0]插入到新數組C[0]的位置,然后用A[1] 繼續與B[0] 進行比較,如果A[1]<B[0], 則,A[1]繼續向新數組插入數據,反之,則B[0]向新數組插入數據,依次循環,將兩個數組的元素插入新數組:
這樣就大功告成了? hey, 等等,如果數組A中的元素都加到新數組中了,數組B中還有元素怎么辦?或者反過來,數組B中的元素都加到新數組中了,但數組A中還有元素怎么辦?沒錯,由於數組是有序的,這時候,可以完全放心地把剩下的元素直接插入新數組中,因此,這里需要有兩種情況,第一,還存在數組A中的待插入元素,第二,還存在數組B中的待插入元素,很簡單,只需要遍歷剩下的所有元素,將其一一加入到新數組即可。
因此,整個算法的代碼應該如下:
再看看這個算法的時間復雜度,沒有嵌套的循環,算法復雜度為O(N), 比第二種情況的效率高了一倍,看來待合並數組是否有序這個條件,真的很重要啊~~
更多內容可以掃描下面二維碼關注微信公眾號