我的一个QuickSort出现了栈溢出,怎么解决。

vczxh 2009-11-11 03:06:03
我目的是学习数据结构,在QuickSort算法种如果是1000000个随机数,0.6s就完成排序。
1.但是,如果是rand()%2,这样的随机数就会出现栈溢出,这个问题很棘手,为了保持QuickSort的快速性,请问怎么解决栈溢出这个问题。

2.及时侥幸没有出现栈溢出,如果情况还是rand()%2,这样的随机数,计算时间将达到17s,请问这个问题怎么解决。
另附上源代码:
void SwitchNum(int& n1,int& n2)
{
int nTemp=n1;
n1=n2;
n2=nTemp;
}

void QuickSort(int *pnArray,int nSize)
{
if (nSize>1)
{
int nNum=nSize/2,i=0,j=nSize-1;
while (i!=j)
{
for (;j>nNum;j--)
{
if (pnArray[nNum]>pnArray[j])
{
SwitchNum(pnArray[nNum],pnArray[j]);
nNum=j;
break;
}
}
for (;i<nNum;i++)
{
if (pnArray[nNum]<pnArray[i])
{
SwitchNum(pnArray[nNum],pnArray[i]);
nNum=i;
break;
}
}
}
QuickSort(pnArray,nNum);
QuickSort(pnArray+nNum+1,nSize-nNum-1);
}
}
...全文
362 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
hh_xj 2009-11-14
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 silitex 的回复:]
引用 10 楼 oyzdz1988 的回复:
使用随机快排吧~

随机快排应该也解决不了random()%2的所引申的问题!根据我的理解,当出现这样的数据时,最好的就是换另外一种排序方法!比如那边提到的BitSort, 用于排序random()%2等这样的小范围数据很有效!在时间复杂度O(nlogm)就行了,因为m=2,所以就会演变成O(n)的排序!
[/Quote]
如果这里的栈溢出,是因为递归函数调用太深的话,用随机快排可以在期望上改善这个问题。快排的最坏时间复杂度是O(n^2),最坏情况下,递归深度是O(n),如果每次的选择的基准可以平衡的划分两子问题,那才有O(lgn)的递归调用深度,随机化选择基准就是这个为了目的。

你说的bitsort应该是一种线性排序吧,据我所知,线性排序要么对关键值的大小有限定,要么隐含在时间复杂度里的常数因子很大,实际上不够通用。
zhangrenhui 2009-11-14
  • 打赏
  • 举报
回复
up
Silitex 2009-11-14
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 oyzdz1988 的回复:]
使用随机快排吧~
[/Quote]
随机快排应该也解决不了random()%2的所引申的问题!根据我的理解,当出现这样的数据时,最好的就是换另外一种排序方法!比如那边提到的BitSort, 用于排序random()%2等这样的小范围数据很有效!在时间复杂度O(nlogm)就行了,因为m=2,所以就会演变成O(n)的排序!
Silitex 2009-11-14
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 hh_xj 的回复:]
引用 8 楼 silitex 的回复:
引用 6 楼 hh_xj 的回复:
引用 5 楼 silitex 的回复:
计算时间将达到17s: 这个用快速排序无法解决,倒是介绍你看另外一种排序方法,最坏时间复杂度:O(nlogn), 最坏空间复杂度O(logn),排序算法见地址:
http://bbs.emath.ac.cn/viewthread.php?tid=1884&extra=&page=1


quicksort是inplace的排序吧,哪需要额外的空间??

哥们,什么叫inplace排序?是指交换排序?还是指选择排序?插入排序?归并排序?不懂这个英文是什么意思!

呵呵,是说除了输入数据所需的空间,不用再创建非常数大小的额外空间来辅助。比如合并排序的合并就用了O(n)的额外空间。
[/Quote]
嗯,明白您的意思了!
oyzdz1988 2009-11-13
  • 打赏
  • 举报
回复
使用随机快排吧~
hh_xj 2009-11-13
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 silitex 的回复:]
引用 6 楼 hh_xj 的回复:
引用 5 楼 silitex 的回复:
计算时间将达到17s: 这个用快速排序无法解决,倒是介绍你看另外一种排序方法,最坏时间复杂度:O(nlogn), 最坏空间复杂度O(logn),排序算法见地址:
http://bbs.emath.ac.cn/viewthread.php?tid=1884&extra=&page=1


quicksort是inplace的排序吧,哪需要额外的空间??

哥们,什么叫inplace排序?是指交换排序?还是指选择排序?插入排序?归并排序?不懂这个英文是什么意思!
[/Quote]
呵呵,是说除了输入数据所需的空间,不用再创建非常数大小的额外空间来辅助。比如合并排序的合并就用了O(n)的额外空间。
Silitex 2009-11-13
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 hh_xj 的回复:]
引用 5 楼 silitex 的回复:
计算时间将达到17s: 这个用快速排序无法解决,倒是介绍你看另外一种排序方法,最坏时间复杂度:O(nlogn), 最坏空间复杂度O(logn),排序算法见地址:
http://bbs.emath.ac.cn/viewthread.php?tid=1884&extra=&page=1


quicksort是inplace的排序吧,哪需要额外的空间??
[/Quote]
哥们,什么叫inplace排序?是指交换排序?还是指选择排序?插入排序?归并排序?不懂这个英文是什么意思!
Silitex 2009-11-12
  • 打赏
  • 举报
回复
计算时间将达到17s: 这个用快速排序无法解决,倒是介绍你看另外一种排序方法,最坏时间复杂度:O(nlogn), 最坏空间复杂度O(logn),排序算法见地址:
http://bbs.emath.ac.cn/viewthread.php?tid=1884&extra=&page=1
Silitex 2009-11-12
  • 打赏
  • 举报
回复
还有,栈溢出的原因:递归太深,每次rand()%2快速排序的递归深度都为O(n),所以必然溢出!
Silitex 2009-11-12
  • 打赏
  • 举报
回复
给你一个我改装后的微软的快速排序的源代码,这个代码的最坏情况的空间复杂度为O(logn),比普通快速排序的最坏空间复杂度O(nlogn)有很大的改善:
#define CUTOFF 8            /* testing shows that this is good value */
static void shortsort (ELEM_TYPE *pData, int lo, int hi)
{
int i;
int max;

while (hi > lo) {
max = lo;
for (i = lo+1; i <= hi; i++) {
if (pData[i].eKey > pData[max].eKey) {
max = i;
}
}
if (max != hi) {
DsSwapElem(&pData[max], &pData[hi]);
}
hi--;
}
}
// 对微软写的快速排序的翻译,这样便于调试,也便于理解微软所写的快速排序的思想
void QuickSortMs(ELEM_TYPE *pData, int nLen)
{
#define STKSIZ (8*sizeof(nLen)-2)
int lo, hi; /* ends of sub-array currently sorting */
int mid; /* points to middle of subarray */
int loguy, higuy; /* traveling pointers for partition step */
int size; /* size of the sub-array */
int lostk[STKSIZ], histk[STKSIZ];
int stkptr; /* stack for saving sub-array to be processed */

if (nLen < 2)
return; /* nothing to do */

stkptr = 0; /* initialize stack */
lo = 0;
hi = nLen-1; /* initialize limits */

/* this entry point is for pseudo-recursion calling: setting
lo and hi and jumping to here is like recursion, but stkptr is
prserved, locals aren't, so we preserve stuff on the stack */
recurse:
size = hi - lo + 1; /* number of el's to sort */

/* below a certain size, it is faster to use a O(n^2) sorting method */
if (size <= CUTOFF) {
shortsort(pData, lo, hi);
}
else {
/* First we pick a partititioning element. The efficiency of the
algorithm demands that we find one that is approximately the
median of the values, but also that we select one fast. Using
the first one produces bad performace if the array is already
sorted, so we use the middle one, which would require a very
wierdly arranged array for worst case performance. Testing shows
that a median-of-three algorithm does not, in general, increase
performance. */

mid = lo + size / 2;
DsSwapElem(&pData[mid], &pData[lo]);

/* We now wish to partition the array into three pieces, one
consisiting of elements <= partition element, one of elements
equal to the parition element, and one of element >= to it. This
is done below; comments indicate conditions established at every
step. */

loguy = lo;
higuy = hi + 1;

/* Note that higuy decreases and loguy increases on every iteration,
so loop must terminate. */
for (;;) {
/* lo <= loguy < hi, lo < higuy <= hi + 1,
A[i] <= A[lo] for lo <= i <= loguy,
A[i] >= A[lo] for higuy <= i <= hi */

do {
loguy++;
} while (loguy <= hi && pData[loguy].eKey <= pData[lo].eKey);

/* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
either loguy > hi or A[loguy] > A[lo] */

do {
higuy--;
} while (higuy > lo && pData[higuy].eKey >= pData[lo].eKey);

/* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
either higuy <= lo or A[higuy] < A[lo] */

if (higuy < loguy)
break;

/* if loguy > hi or higuy <= lo, then we would have exited, so
A[loguy] > A[lo], A[higuy] < A[lo],
loguy < hi, highy > lo */

DsSwapElem(&pData[loguy], &pData[higuy]);

/* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
of loop is re-established */
}

/* A[i] >= A[lo] for higuy < i <= hi,
A[i] <= A[lo] for lo <= i < loguy,
higuy < loguy, lo <= higuy <= hi
implying:
A[i] >= A[lo] for loguy <= i <= hi,
A[i] <= A[lo] for lo <= i <= higuy,
A[i] = A[lo] for higuy < i < loguy */

DsSwapElem(&pData[lo], &pData[higuy]); /* put partition element in place */

/* OK, now we have the following:
A[i] >= A[higuy] for loguy <= i <= hi,
A[i] <= A[higuy] for lo <= i < higuy
A[i] = A[lo] for higuy <= i < loguy */

/* We've finished the partition, now we want to sort the subarrays
[lo, higuy-1] and [loguy, hi].
We do the smaller one first to minimize stack usage.
We only sort arrays of length 2 or more.*/

if ( higuy - 1 - lo >= hi - loguy ) {
if (lo + 1 < higuy) {
lostk[stkptr] = lo;
histk[stkptr] = higuy - 1;
++stkptr;
} /* save big recursion for later */

if (loguy < hi) {
lo = loguy;
goto recurse; /* do small recursion */
}
}
else {
if (loguy < hi) {
lostk[stkptr] = loguy;
histk[stkptr] = hi;
++stkptr; /* save big recursion for later */
}

if (lo + 1 < higuy) {
hi = higuy - 1;
goto recurse; /* do small recursion */
}
}
}

/* We have sorted the array, except for any pending sorts on the stack.
Check if there are any, and do them. */

--stkptr;
if (stkptr >= 0) {
lo = lostk[stkptr];
hi = histk[stkptr];
goto recurse; /* pop subarray from stack */
}
else {
return; /* all subarrays done */
}
}
fire_woods 2009-11-12
  • 打赏
  • 举报
回复
遞歸需要空間的.
hh_xj 2009-11-12
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 silitex 的回复:]
计算时间将达到17s: 这个用快速排序无法解决,倒是介绍你看另外一种排序方法,最坏时间复杂度:O(nlogn), 最坏空间复杂度O(logn),排序算法见地址:
http://bbs.emath.ac.cn/viewthread.php?tid=1884&extra=&page=1
[/Quote]

quicksort是inplace的排序吧,哪需要额外的空间??
xingzhe2001 2009-11-11
  • 打赏
  • 举报
回复
栈溢出可能由于两个原因,递归太深或者局部变量太大。
对于递归太深可以减少数据量或者改用堆栈这种数据结构实现
对于局部变量太大可以把局部变量放到全局变量
fire_woods 2009-11-11
  • 打赏
  • 举报
回复
隨機數在哪里?

33,028

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧