我对堆栈溢出没有多少经验,我认为它们是由超过某个递归深度的递归函数引起的,为什么它们会在这个迭代实现的合并排序中出现!
#include<iostream>
#include <stdlib.h>
#define SIZE 3000000
int L[2500002];
int R[2500002];
using namespace std;
int min(int a, int b) {
return !(b<a) ? a : b;
}
void Merge(int data[], int p, int q, int r)
{
if (q >= SIZE)q = (r + p) / 2;
int sizeL = q - p + 2;
int sizeR = r - q + 1;
for (int i = 0; i < sizeL - 1; i++)
L[i] = data[i + p];
for (int i = 0; i < sizeR - 1; i++)
R[i] = data[i + q + 1];
int max;
if (L[sizeL - 2]>R[sizeR - 2])
max = L[sizeL - 2] + 1;
else
max = R[sizeR - 2] + 1;
L[sizeL - 1] = R[sizeR - 1] = max;
int indexL = 0, indexR = 0;
for (int i = p; i <= r; i++){
if (L[indexL] <= R[indexR]){
data[i] = L[indexL];
indexL++;
}
else{
data[i] = R[indexR];
indexR++;
}
}
}
void MergeSort(int data[], int p, int r)
{
for (int i = 1; i< SIZE; i *= 2)
for (int j = 0; j < SIZE; j += 2 * i)
Merge(data, j, j + i - 1, min((j + 2 * i - 1), SIZE - 1));
}
/*****************************************************************************/
bool IsSorted(int data[], int size)
{
int i;
for (i = 0; i<(size - 1); i++)
{
if (data[i] > data[i + 1])
return false;
}
return true;
}
int main()
{
int data[SIZE];
for (int i = 0; i < SIZE; i++)
data[i] = rand();
MergeSort(data,0,SIZE-1);
if(IsSorted(data, SIZE))
cout << "Sorted correctly";
else
cout << "incorrect sorting";
getchar();
return 0;
}
答案 0 :(得分:3)
int main()
{
int data[SIZE];
...
在堆栈上声明数组。堆栈大小有限制。它因操作系统和配置而异,但它可能很容易小于12 MB,即您要求的数量(假设为32位整数)。尝试使用std::vector
在堆上分配您的数组。
编译器无法就此问题向您发出警告,因为堆栈大小是由OS在加载程序时设置的。你可以重新配置你的操作系统默认使用一个小堆栈,之前工作的程序会突然开始溢出。
如果您有兴趣了解操作系统如何检测堆栈溢出,请查看虚拟内存,MMU和Guard页面。
答案 1 :(得分:1)
不确定这是否是问题,但your merge sort seems buggy。
使用无符号整数而不是签名。
答案 2 :(得分:0)
class cSort_t
{
public:
template <typename T>
static void insertionSort (T* _array, const unsigned size);
template <typename T>
static void mergeSort(T *data, const unsigned size);
protected:
cSort_t ();
~cSort_t ();
cSort_t (const cSort_t& ref);
const cSort_t& operator= (const cSort_t& ref);
private:
template <typename T>
_inline static void copyElements(T * dst,T * src, unsigned size);
};
//----------------- Insertion Sort --------------------
// standard insertion sort routine
template <typename T>
void cSort_t::insertionSort (T* _array, const unsigned size)
{
T _temp;
for (int unsorted = 1; unsorted<(int)size; ++unsorted)
{
_temp = *(_array+unsorted);
for (int index = unsorted-1; index>=0; --index)
{
if (_temp < *(_array+index))
{
*(_array+index+1) = *(_array+index);
if (0==index)
*_array = _temp;
}
else
{
*(_array+index+1) = _temp;
break;
}
}
}
}
// copyElements - simple loop unrolling of data array copy
// to remove some overhead of looping.
template <typename T>
__inline void cSort_t::copyElements(T * dst, T * src, int size)
{
while(size > 3)
{
*(dst+0) = *(src+0);
*(dst+1) = *(src+1);
*(dst+2) = *(src+2);
*(dst+3) = *(src+3);
dst+=4;
src+=4;
size-=4;
};
while(size > 0)
{
*dst++ = *src++;
size--;
};
}
//----------------- Merge Sort Function ----------------------
// A bottom's up iterative merge sort.
// Internal working buffer(temp[size]).
// Simple ping-pong buffering to reduce copy backs.
// Stable sort, maximum sort complexity=O(n*log n).
// Faster then most sorts for general purpose use.
// Returns the sorted result in the input buffer.
// Use: cSort_t::mergeSort(data_array, size_of_array);
// The reason for the speed up is simpler loops, pointer manipulation,
// no copy backs, recursive calls and storage re-creation.
template <typename T>
void cSort_t::mergeSort(T *data, unsigned size)
{
// use insertion sort for sorting small arrays
if(size < 32)
{
insertionSort (data, size);
return;
}
unsigned int i,sp0c,sp1,sp1c;
T *p0,*p1,*tmp,*tp1,*tp2;
T *temp = new T [size]; // create an internal working temp
// do easy first pass of bottoms up merge sort
// calculate the number of passes used by algorithm to
// make the final sorted data end up back in input array to save moves.
// by using either an initial in-place compare swap or a out-place compare move.
i=0; for(unsigned j=1; j<size; j <<= 1) i++; // 2**i >= size
if(i&1)
{
// calculated odd number of passes
// do the in-place compare and swap
// to make last pass sorted data to end in the input buffer.
p0 = data;
for(i=1; i<size; i+=2, p0+=2)
{
if(*p0 > *(p0+1)) {*temp = *p0; *p0 = *(p0+1); *(p0+1) = *temp;}
}
tp1 = data;
tp2 = temp;
}
else
{
// calculated even number of passes
// do an out of place compare and move
// to make last pass sorted data to end in the input buffer.
p0 = data;
p1 = temp;
for(i=1; i<size; i+=2, p0+= 2, p1+= 2)
{
if(*p0 <= *(p0+1)) {*p1 = *p0; *(p1+1) = *(p0+1);}
else {*p1 = *(p0+1); *(p1+1) = *p0;}
}
if(size&1) *p1 = *p0; // move last "odd" word
tp1 = temp;
tp2 = data;
}
// do more complex part of the bottoms up merge sort
// instead of using a half way split use a binary split
// only complication added is handing the right side element's remainder.
//
// group 1 group n-1 group n
// [ 5 9 | 7 2 ] [ 3 6 | 4 9 ] [ 7 6 | 5 ]
// ^ ^ ^ ^ ^ ^
// lsp rsp lsp rsp lsp rsp
//
p0 = tp1; // p0 points to data elements be sorted
tmp = tp2; // tmp points to where to put results this pass
// for each pass of the bottoms up merge sort
for(i=2; i<size; i<<=1)
{
p1 = p0 + i; // calculate first groups' right side pointer
sp1 = size - i; // and number of elements past that pointer(inclusive)
// do merge for all groups in this merge pass
for(;;)
{
sp0c = i; // number of left side elements in group
sp1c = i; // number of right side elements in group
// on last group left and right lengths are different.
if(sp1 < i) sp1c = sp1;
// do a merge pass on a group
for(;;)
{
if(*p0 <= *p1) // simple compare merge pass
{
*tmp++ = *p0++; // move a left side element
if((--sp0c) == 0) break;
}
else
{
*tmp++ = *p1++; // move a right side element
if((--sp1c) == 0) break;
}
}
// we always have a few unmerged elements on left or right side
if(sp0c != 0)
{
// move what's remaining of left side's elements
do {*tmp++ = *p0++;} while((--sp0c) != 0);
}
else
{
// move what's remaining of right side's elements
do {*tmp++ = *p1++;} while((--sp1c) != 0);
}
p0 = p1; // adjust left side and right side pointer
p1 += i; // for next group
if(sp1 <= (i<<1)) break;
sp1 -= (i<<1);
}
// All groups processed except for possibly the last group
// because it may not have had a right side to sort.
// if any remaining data copy it(partially sorted in previous passes)
if(sp1 > i)
{
copyElements(tmp, p0, (sp1-i));
}
// swap working pointers instead of copying temp array back to data array
p0 = tp2;
tmp = tp2 = tp1;
tp1 = p0;
}
// delete internal working temp, sorted data should be back in input.
delete [] temp;
}