9.1A和B是兩個有序數組(假設為遞增序列),而且A的長度足以放下A和B中所有的元素, 寫一個函數將數組B融入數組A,並使其有序


題目

原文:

You are given two sorted arrays, A and B, and A has a large enough buffer at the end to hold B. Write a method to merge B into A in sorted order.

譯文:

A和B是兩個有序數組(假設為遞增序列),而且A的長度足以放下A和B中所有的元素, 寫一個函數將數組B融入數組A,並使其有序。

解答

最簡單的方法是開一個大小可以容納A和B的數組C,然后像歸並排序中合並兩個數組一樣, 按照大小順序把數組A和數組B的元素一一地放入數組C,然后再將數組C拷貝給A。 這種方法額外地使用了O(n)的空間,顯然這是沒有必要的開銷。由於A的大小已經足夠用了, 所以直接在A上直接操作即可。

可是如果我們思維定勢地對比數組A和數組B,每次取小的元素放入數組A, 這樣就會發現,要放入的位置上正放着有用的元素。處理起來就麻煩了。

相反,如果我們從A和B的尾部元素開始對比,每次取大的元素放在數組A的尾部, 這樣一來,要放入的位置就不會出現上面的沖突問題。當對比結束時, 即可得到一個排好序的數組A。代碼如下:

#include <iostream> using namespace std; void merge(int a[], int b[], int n, int m){ int k = n + m - 1; int i = n - 1, j = m - 1; while(i>=0 && j>=0){ if(a[i] > b[j]) a[k--] = a[i--]; else a[k--] = b[j--]; } while(j>=0) a[k--] = b[j--]; } int main(){ int a[15] = { 1, 3, 7, 8, 9 }; int b[] = { 2, 4, 5, 6, 10 }; int n = 5, m = 5; merge(a, b, 5, 5); for(int i=0; i<m+n; ++i) cout<<a[i]<<" "; return 0; }

對比結束后,要檢查數組B中是否還有元素,有的話要將它們拷貝到數組A。 我們並不需要檢查數組A,因為如果數組A還有元素,說明while循環是因為數組B 中沒有元素了才退出的。而A中的元素本來就是有序且就位於數組A中,所以不需要再管它。 如果A和B中的元素個數為n和m,則該算法的時間復雜度為O(n+m)。

讓我們再加點限制條件,如果兩個有序的序列並且沒有額外的空間,那要怎么排序。 比如對於數組A,它的前半段和后半段分別有序,不使用額外的空間怎么使A整體有序。

首先,不可避免的我們還是要將兩個有序部分中的元素拿出來對比。 我們先拿出前半段的第一個元素和后半段的第一個元素進行對比, 如果后半段的第一個元素要小,就將它們交換。由於這兩個元素是各自序列的最小值, 這一對比就將整個數組A的最小值取出放在了正確的位置上。然后呢? 交換到后半段的那個值怎么辦?不理它,不太合適吧。我們可以通過兩兩對比, 把它移動到后半段的某個位置,使后半段保持有序。接下來呢? 我們取出前半段的第2個元素(第1個元素已經放在它正確的位置上,不用理它了), 還是和后半段的第1個元素對比,這一對比中較小的就會是整個數組中第2小的元素, 如果是后半段那個元素較小,則交換它們,然后仍然移動后半段使其保持有序。 這樣不斷進行下去,當把前半段的元素都遍歷操作一遍,就會將小的元素都移動到前半段, 並且是有序的。而大的元素都在后半段且也是有序的。排序結束。

代碼如下:

#include <iostream> using namespace std; void swap(int &a, int &b){ a = a^b; b = a^b; a = a^b; } void merge(int a[], int begin, int mid , int end){ for(int i=begin; i<=mid; ++i){ if(a[i]>a[mid+1]){ swap(a[i], a[mid+1]); for(int j=mid+1; j<end; ++j){ if(a[j]<=a[j+1]) break; swap(a[j], a[j+1]); } } } } int main(){ int a[10] = { 8, 9, 11, 15, 17, 1, 3, 5, 12, 18 }; int b[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; merge(a, 0, 4, 9); for(int i=0; i<10; ++i) cout<<a[i]<<" "; return 0; }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM