0

處理一個類項目,我需要實現一個合併排序來排序500,000個項目。 經過多次嘗試後,我嘗試在線尋找源代碼,並在這裏找到了一些:http://www.sanfoundry.com/cpp-program-implement-merge-sort/合併排序:堆損壞刪除[]

我必須更改代碼以使用動態數組(大小)。當程序運行合併函數時,我使用要合併的元素(或高)數創建一個新的動態數組。一旦函數完成排序並將它們合併到原始數組中,我在新的動態數組上使用delete []。這是我得到「檢測到堆損壞」錯誤的地方。

下面是代碼(文字牆):

//Heap Sort 

#include <iostream> 
#include <fstream> 
#include <sstream> 
#include <ctime> 
#include <stdlib.h> 
#include <stdio.h> 

using namespace std; 

//Function Prototypes 
void mergesort(int *a, int low, int high); 
void merge(int *a, int low, int high, int mid); 


int main() 
{ 
//Start with element 1 of the array 
int line_no = 0; 
int num; 
int array_size = 500000; 
int* num_array = new int[array_size]; 

//Open file for input 
fstream in_file("CSCI3380_final_project_dataset.txt", ios::in); 

//Test for file opening 
if (!in_file) 
{ 
    cout << "Cannot open words1.txt for reading" << endl; 
    exit(-1); 
} 

//Read file 
while(true) 
{ 
    //Read one line at a time 
    in_file >> num; 

    //Test for eof 
    if (in_file.eof()) 
     break; 

    num_array[line_no] = num; 

    //Increment array position 
    line_no++; 

} 

//Close the file 
in_file.close(); 

//Start Time 
clock_t time_a = clock(); 

//Run Sorting Algorithim 
mergesort(num_array, 0, array_size-1); 

//End Time 
clock_t time_b = clock(); 



//Elapsed Time 
if (time_a == ((clock_t)-1) || time_b == ((clock_t)-1)) 
{ 
    cout << "Unable to calculate elapsed time" << endl; 
} 
else 
{ 
    int total_time_ticks = time_b - time_a; 
    cout << "Elapsed time: " << total_time_ticks << endl; 
} 

delete[] num_array; 

return 0; 
} 

void mergesort(int *a, int low, int high) 

{ 

int mid; 

if (low < high) 

{ 

    mid=(low+high)/2; 

    mergesort(a,low,mid); 

    mergesort(a,mid+1,high); 

    merge(a,low,high,mid); 

} 

return; 

} 

void merge(int *a, int low, int high, int mid) 

{ 


//--------------------------Create new array------------------------------- 

int* sort_array = new int[high]; 

//--------------------------New Array Created----------------------------- 

int i, j, k; 

i = low; 

k = low; 

j = mid + 1; 

while (i <= mid && j <= high) 

{ 

    if (a[i] < a[j]) 

    { 

     sort_array[k] = a[i]; 

     k++; 

     i++; 

    } 

    else 

    { 

     sort_array[k] = a[j]; 

     k++; 

     j++; 

    } 

} 

while (i <= mid) 

{ 

    sort_array[k] = a[i]; 

    k++; 

    i++; 

} 

while (j <= high) 

{ 

    sort_array[k] = a[j]; 

    k++; 

    j++; 

} 

for (i = low; i < k; i++) 

{ 

    a[i] = sort_array[i]; 

} 

//---------------------------Delete the New Array-------------------- 

delete[] sort_array; 

//--------------------------Oh No! Heap Corruption!------------------ 

} 
+0

你很喜歡空白! :D – Rubens

+2

C++的第一條規則:不要做你自己的內存管理。 –

+1

我想你正在訪問你在合併中創建的sort_array的末尾1。你不能訪問sort_array [高]。 – drescherjm

回答

2

我就不告訴你「你應該使用矢量」,「你應該用智能指針」等等。你是應該的,我會留下來的。關於你的實際問題....

你正在寫你的數組的分配空間。分配的大小爲high

int* sort_array = new int[high]; 

這意味着你可以從0..(high-1)只能提領。然而這樣的:

while (j <= high) 
{ 
    sort_array[k] = a[j]; 
    k++; 
    j++; 
} 

是保證寫入sort_array[high],因此調用未定義行爲一個位置。


一種不同的方法

歸併爲約DIV-2分區。你知道這個。你可能不是已經考慮到,C和C++都執行指針運算美麗因此,你只需要兩個參數爲mergesort():一個基地址和一個長度。其餘的可以照顧你與指針數學:

考慮一下:

void mergesort(int *a, int len) 
{ 
    if (len < 2) 
     return; 

    int mid = len/2;  
    mergesort(a, mid); 
    mergesort(a + mid, len-mid); 
    merge(a, mid, len); 
} 

而一個merge實現,它看起來像這樣:

void merge(int *a, int mid, int len) 
{ 
    int *sort_array = new int[ len ]; 
    int i=0, j=mid, k=0; 

    while (i < mid && j < len) 
    { 
     if (a[i] < a[j]) 
      sort_array[k++] = a[i++]; 
     else 
      sort_array[k++] = a[j++]; 
    } 

    while (i < mid) 
     sort_array[k++] = a[i++]; 

    while (j < len) 
     sort_array[k++] = a[j++]; 

    for (i=0;i<len;++i) 
     a[i] = sort_array[i]; 

    delete[] sort_array; 
} 

main()像下面這樣調用。注:我已刪除的文件I/O代替隨機生成的只是爲了更容易地測試:

#include <iostream> 
#include <ctime> 
#include <cstdlib> 
#include <cstdio> 
using namespace std; 

//Function Prototypes 
void mergesort(int *a, int len); 
void merge(int *a, int mid, int len); 

int main() 
{ 
    std::srand((unsigned int)std::time(nullptr)); 

    // Start with element 1 of the array 
    int array_size = 500000; 
    int* num_array = new int[array_size]; 
    std::generate_n(num_array, array_size, std::rand); 

    // Start Time 
    clock_t time_a = clock(); 

    // Run Sorting Algorithim 
    mergesort(num_array, array_size); 

    // End Time 
    clock_t time_b = clock(); 

    //Elapsed Time 
    if (time_a == ((clock_t)-1) || time_b == ((clock_t)-1)) 
    { 
     cout << "Unable to calculate elapsed time" << endl; 
    } 
    else 
    { 
     int total_time_ticks = time_b - time_a; 
     cout << "Elapsed time: " << total_time_ticks << endl; 
    } 

    delete[] num_array; 

    return 0; 
} 

這導致是經過時間:

Elapsed time: 247287 

更高效

現在你已經看到,除了你的序列之外,你最多還需要N空間。最上面的合併應該是足夠的證據。你可能想要的是而不是考慮的是,實際上是正好是你需要的空間,如果你願意,你可以預先分配它並在整個算法中使用它。你可以保留當前包埋於mergesort(),但我們會與前部裝載機分配所有我們永遠需要的空間一次被包裹起來:

// merges the two sequences a[0...mid-1] and a[mid...len-1] 
// using tmp[] as the temporary storage space 
static void merge_s(int *a, int *tmp, int mid, int len) 
{ 
    int i=0, j=mid, k=0; 

    while (i < mid && j < len) 
    { 
     if (a[i] < a[j]) 
      tmp[k++] = a[i++]; 
     else 
      tmp[k++] = a[j++]; 
    } 

    while (i < mid) 
     tmp[k++] = a[i++]; 

    while (j < len) 
     tmp[k++] = a[j++]; 

    for (i=0;i<len;++i) 
     a[i] = tmp[i]; 
} 

static void mergesort_s(int *a, int *tmp, int len) 
{ 
    if (len < 2) 
     return; 

    int mid = len/2; 
    mergesort_s(a, tmp, mid); 
    mergesort_s(a + mid, tmp+mid, len-mid); 
    merge_s(a, tmp, mid, len); 
} 

void mergesort(int *a, int len) 
{ 
    if (len < 2) 
     return; 

    int *tmp = new int[len]; 
    mergesort_s(a,tmp,len); 
    delete [] tmp; 

} 

這導致了一個經過時間:

Elapsed time: 164704 

大大好過我們以前。祝你好運。

1

使用一對函數來控制合併的方向可以避免WhozCraig代碼示例中顯示的複製步驟(注意 - 自底向上合併仍然會更快)。

注 - 我不會推薦使用WhozCraig或我的代碼示例,因爲這些方法可能不在您的課程中,並且應該根據您在課堂上教授的內容編寫代碼。我不知道你的課程是否涵蓋了合併排序,所以我沒有發佈它的例子。

mergesort_s(int *a, int *tmp, int len) 
{ 
// ... 
    mergesort_atoa(a, tmp, 0, len); 
// ... 
} 

mergesort_atoa(int *a, int *tmp, int low, int end) 
{ 
    if((end - low) < 2){ 
     return; 
    } 
    int mid = (low + end)/2; 
    mergesort_atot(a, tmp, low, mid); 
    mergesort_atot(a, tmp, mid, end); 
    merge_s(tmp, a, low, mid, end); 
}  

mergesort_atot(int *a, int *tmp, int low, int end) 
{ 
    if((end - low) < 2){ 
     tmp[0] = a[0]; 
     return; 
    } 
    int mid = (low + end)/2; 
    mergesort_atoa(a, tmp, low, mid); 
    mergesort_atoa(a, tmp, mid, end); 
    merge_s(a, tmp, low, mid, end); 
}  

void merge_s(int *src, int *dst, int low, int mid, int end) 
{ 
    int i = low;     // src[] left index 
    int j = mid;     // src[] right index 
    int k = low;     // dst[]  index 
    while(1){      // merge data 
     if(src[i] <= src[j]){  // if src[i] <= src[j] 
      dst[k++] = src[i++]; // copy src[i] 
      if(i < mid)    // if not end of left run 
       continue;   //  continue (back to while) 
      while(j < end)   // else copy rest of right run 
       dst[k++] = src[j++]; 
      return;     //  and return 
     } else {     // else src[i] > src[j] 
      dst[k++] = src[j++]; // copy src[j] 
      if(j < end)    // if not end of right run 
       continue;   //  continue (back to while) 
      while(i < mid)   // else copy rest of left run 
       dst[k++] = src[i++]; 
      return;     //  and return 
     } 
    } 
}