簡體   English   中英

數組和C ++中的mergeSort?

[英]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]數組,並通過mergeSortMerge傳遞它,並在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個錯誤的一些解釋:

  1. 您不希望每次都使用hi + 1大小的數組,當您沿着“合並樹”瀏覽時,必須合並較小大小的數組,因此需要使用hi - lo + 1 實際上,在這種情況下,使用hi + 1應該不是問題,但是您分配的內存超出了實際需要。

  2. 您不應該從lo開始,而應該從0 ,否則您的tArray[count]tArray[count] 在您的情況下,從lo開始工作是因為您要分配一個非常大的數組(大小為20hi + 1 ),但不適用於大小為hi - lo + 1的數組,因此請務必小心。

  3. 也許是最大的錯誤-您一直在替換原始數組的第一個count單元...不! 您要替換lohi之間的單元格,而不是0count之間的單元格。

您需要記住,在調用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 = 0hi = 3 )和[93, 76, 81, 76]lo = 4hi = 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. 您應該已經注意到,由於要合並兩個大小為1的數組( [93][76] ),因此需要一個大小為2的臨時數組。如果使用tArray[hi + 1] ,則分配一個大小為hi + 1 = 6的數組hi + 1 = 6 ,這比您實際需要的要大得多(在這里可能不會有很大的不同,但是請想象您是否有原始大小為10億的數組!)。 因此,分配大小為hi - lo + 1 = 5 - 4 + 1 = 2的數組就足夠了。

  2. 您實際上是初始數組的45范圍,因此您要處理該部分,而又不想刪除已經排序的01部分! 但是,如果在循環中執行array[i] = tArray[i] ,會發生什么? 好吧, i0開始並開始count (在這種情況下應該為2 ),所以您要替換array[0]array[1]而不是array[4]array[5] 這可以通過執行array[lo + i]而不是array[i]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM