处理一个类项目,我需要在其中实现一个Merge Sort来排序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 :(得分:2)
我会饶你&#34;你应该使用矢量&#34;,&#34;你应该使用智能指针&#34;等等你应该是,而且我会留在那。关于你的实际问题......
您正在编写一个超过阵列分配空间的内容。分配的大小为high
:
int* sort_array = new int[high];
意味着您只能从0..(high-1)
取消引用。但是这个:
while (j <= high)
{
sort_array[k] = a[j];
k++;
j++;
}
是一个保证写入sort_array[high]
的位置,因此会调用未定义的行为。
不同的方法
Mergesort是关于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()
的当前截留,但我们将使用前端加载器将其包装起来,前端加载器分配我们曾经需要一次的所有空间:< / p>
// 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 :(得分: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
}
}
}