[英]Arrays and mergeSort in c++?
void Merge(int *array, int lo, int mid, int hi) {
int tArray[20];
int loBeg = lo;
int count = lo;
int hiBeg = mid + 1;
while (loBeg <= mid && hiBeg <= hi) {
if (array[loBeg] < array[hiBeg]) {
tArray[count] = array[loBeg];
loBeg++;
count++;
} else {
tArray[count] = array[hiBeg];
hiBeg++;
count++;
}
}
while (loBeg <= mid) {
tArray[count++] = array[loBeg++];
}
while (hiBeg <= hi) {
tArray[count++] = array[hiBeg++];
}
for (int i = 0; i < count; i++) {
array[i] = tArray[i];
}
}
void mergeSort(int *array, int lo, int hi) {
if (lo < hi) {
int mid = (lo + hi) / 2;
mergeSort(array, lo, mid);
mergeSort(array, mid + 1, hi);
Merge(array, lo, mid, hi);
}
}
int main(int argc, const char * argv[]) {
int array[] = {90, 99, 63, 82, 93, 76, 81, 76};
//int temp[8];
mergeSort(array, 0, 7);
for (int i = 0; i < 8; i++) {
std::cout << array[i] << std::endl;
}
return 0;
}
我的問題是關於此合並排序代碼期間數組的性質。 該代碼僅在設置為tArray[20];
將初始值設置為20。為什么不能將初始值設置為hi + 1
(在這種情況下為8
(與數組相同)? 但是,如果我取消注釋temp[8]
數組,並通過mergeSort
和Merge
傳遞它,並在Merge
tArray
其用作tArray
(初始大小為8
),那么它將起作用。
我認為我的不了解也是我原始的merge()
)函數(如下所示)也不起作用的原因:
//this was my original merge code which does not work.
void merge(int *array, int lo, int mid, int hi) {
int tempArray[hi + 1];
int loBeg = lo;
int hiBeg = mid + 1;
for (int i = 0; i <= hi; i++) {
if (hiBeg > hi || (array[loBeg] < array[hiBeg] && loBeg <= mid)) {
tempArray[i] = array[loBeg++];
} else {
tempArray[i] = array[hiBeg++];
}
}
for (int i = 0; i <= hi; i++) {
array[i] = tempArray[i];
}
}
因此,基本上我想知道為什么在第一個Merge()
函數中,必須將tArray
初始大小設置為20
而不是與數組相同的大小,除非我從main
傳遞一個臨時數組(初始化為相同的)大小為數組),然后,為什么我原來的merge()
函數不起作用,但是我認為這與我對第一個Merge()函數的理解不足有關。
當您創建這樣的數組時: int array[20];
您將其分配到程序的堆棧存儲器中。 在程序啟動之前分配該內存。
問題來了。 當你嘗試做int array[hi + 1];
您要求它分配程序啟動之前未知的內存量,這會導致錯誤。
在這種情況下,您需要做的是使用動態內存。 運行時將分配並釋放此內存。 意思是你可以做int* array = new int[hi + 1];
並且不會導致錯誤。
整個合並功能為:
void merge(int *array, int lo, int mid, int hi) {
int* tempArray = new int[hi + 1];
int loBeg = lo;
int hiBeg = mid + 1;
for (int i = 0; i <= hi; i++) {
if (hiBeg > hi || (array[loBeg] < array[hiBeg] && loBeg <= mid)) {
tempArray[i] = array[loBeg++];
} else {
tempArray[i] = array[hiBeg++];
}
}
for (int i = 0; i <= hi; i++) {
array[i] = tempArray[i];
}
delete[] tempArray;
}
我不建議您自己管理動態內存。 您應該為此使用STL: vector<int> tempArray(hi + 1);
而不是int* tempArray = new int[hi + 1];
。 這樣,您不必具有delete[] tempArray;
在末尾。
合並排序被認為可用於列表,因為當您合並2個列表時,您可以將每個元素自由地附加到所需的元素上。
例:
Merge(List{3,4},List{5,6});
導致以下操作
List Merge(List a, List b){ //2 instructions even when Lists are long 1000000 elements
List newlist;
newlist.head = a.head;
newlist.tail = b.tail;
a.tail.next = b.head;
b.head.prev = a.tail;
return newList;
}
當您有數組時,實際上必須分配一個新大小的新數組:
int * Merge( int array* a, int array* b, unsigned int sizea, unsigned int sizeb){
//int tArray[20]; // :/ wrong
int * newarray = new int[sizea+sizeb];
for(unsigned int i=0; i<sizea; i++)
newarray[i]=a[i];
for(unsigned int i=0; i<sizeb; i++)
newarray[i+sizea]=a[i];
delete []a;
delete []b;
return newarray;
}
附帶地,這使算法更加昂貴。 即使在您已經預分配了足夠大的數組的情況下,算法的成本也更高,因為您必須在每次合並時復制所有元素。
您的代碼中有多個問題,其中有幾個:
void Merge(int *array, int lo, int mid, int hi) {
// The size should be hi - lo + 1, not hi + 1
int tArray[hi + 1];
int loBeg = lo;
// count should start at 0, not lo
int count = lo;
int hiBeg = mid + 1;
while (loBeg <= mid && hiBeg <= hi) {
if (array[loBeg] < array[hiBeg]) {
tArray[count] = array[loBeg];
loBeg++;
count++;
} else {
tArray[count] = array[hiBeg];
hiBeg++;
count++;
}
}
while (loBeg <= mid) {
tArray[count++] = array[loBeg++];
}
while (hiBeg <= hi) {
tArray[count++] = array[hiBeg++];
}
for (int i = 0; i < count; i++) {
// it should be array[lo + i], not array[i]
array[i] = tArray[i];
}
}
以下是3個錯誤的一些解釋:
您不希望每次都使用hi + 1
大小的數組,當您沿着“合並樹”瀏覽時,必須合並較小大小的數組,因此需要使用hi - lo + 1
。 實際上,在這種情況下,使用hi + 1
應該不是問題,但是您分配的內存超出了實際需要。
您不應該從lo
開始,而應該從0
,否則您的tArray[count]
將tArray[count]
。 在您的情況下,從lo
開始工作是因為您要分配一個非常大的數組(大小為20
或hi + 1
),但不適用於大小為hi - lo + 1
的數組,因此請務必小心。
也許是最大的錯誤-您一直在替換原始數組的第一個count
單元...不! 您要替換lo
和hi
之間的單元格,而不是0
和count
之間的單元格。
您需要記住,在調用Merge (array, lo, mid, hi)
,您想將array[lo:mid]
和array[mid+1:hi]
合並為array[lo:hi]
。
以下是一些詳細說明:
讓我們從下面的數組[90, 99, 63, 82, 93, 76, 81, 76]
mergeSort
[90, 99, 63, 82, 93, 76, 81, 76]
,在對mergeSort
每次調用中,您將數組分為兩個相等的部分:
第一次獲得[90, 99, 63, 82]
( lo = 0
, hi = 3
)和[93, 76, 81, 76]
( lo = 4
, hi = 7
),並且不斷除法直到得到8
個大小為1
數組。 為了簡單起見([90], 0, 0)
我將編寫(array, lo, hi)
,例如([90], 0, 0)
。
您應該到達具有([90], 0, 0)
, ([99], 1, 1)
,依此類推...將這些2乘以2,所以(例如)將要合並([93], 4, 4)
和([76], 5, 5)
。 合並這兩個數組時,您將得到如下所示的Merge
調用:
Merge (array, 4, 4, 5) // mid is (4 + 5) / 2 = 4
那么, Merge
功能會發生什么?
您應該已經注意到,由於要合並兩個大小為1的數組( [93]
和[76]
),因此需要一個大小為2的臨時數組。如果使用tArray[hi + 1]
,則分配一個大小為hi + 1 = 6
的數組hi + 1 = 6
,這比您實際需要的要大得多(在這里可能不會有很大的不同,但是請想象您是否有原始大小為10億的數組!)。 因此,分配大小為hi - lo + 1 = 5 - 4 + 1 = 2
的數組就足夠了。
您實際上是初始數組的4
到5
范圍,因此您要處理該部分,而又不想刪除已經排序的0
到1
部分! 但是,如果在循環中執行array[i] = tArray[i]
,會發生什么? 好吧, i
從0
開始並開始count
(在這種情況下應該為2
),所以您要替換array[0]
和array[1]
而不是array[4]
和array[5]
。 這可以通過執行array[lo + i]
而不是array[i]
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.