我正试图解决对黑客的快速排序 - 2挑战。它说我们必须反复调用分区,直到整个数组都被排序。我的程序适用于某些测试用例,但对于某些测试用例,它会崩溃,快速排序 - 2.exe已停止工作"。我找不到它为什么会发生的原因。 数组/子数组的第一个元素每次都被视为数据元素。
#include <iostream>
#include <conio.h>
using namespace std;
void swap(int arr[], int a, int b)
{
int c = arr[a];
arr[a] = arr[b];
arr[b] = c;
}
void qsort(int arr[], int m, int n) //m - lower limit, n - upper limit
{
if (n - m == 1)
{
return;
}
int p = arr[m], i, j, t; //p - pivot element, t - temporary
//partition
for (int i = m+1; i < n; i++)
{
j = i;
if (arr[j] < p)
{
t = arr[j];
while (arr[j] != p)
{
arr[j] = arr[j-1];
j--;
}
arr[j] = t; //pivot is at j and j+1
}
}
//check if sorted
int f = 1;
while (arr[f] > arr[f-1])
{
if (f == n-1)
{
f = -1;
break;
}
f++;
}
if (f == -1)
{
cout << "Sub Array Sorted\n";
}
else
{
if (p == arr[m]) //pivot is the smallest in sub array
{
qsort(arr, m+1, n); //sort right sub array
}
else
{
qsort(arr, m, j+1); //sort left sub array
qsort(arr, j+1, n); //sort right sub array
}
}
}
int main()
{
int n;
cin >> n;
int arr[n];
for (int i = 0; i < n; i++)
{
cin >> arr[i];
}
qsort(arr, 0, n);
for (int i = 0; i < n; i++)
{
cout << arr[i] << " ";
}
return 0;
}
答案 0 :(得分:0)
您的索引超出范围问题。
这不会为您提供解决方案,但它可以帮助您找到程序失败的原因。
我修改了你的程序,因此它使用vector
int
而不是int
的原始数组,当你运行这个程序时,你会得到一个超出范围异常的索引。
触发问题的序列4 3 7 1 6 4
是硬编码的,因此您不需要每次都输入它。
#include <iostream>
#include <vector>
using namespace std;
void swap(vector<int> & arr, int a, int b)
{
int c = arr[a];
arr[a] = arr[b];
arr[b] = c;
}
void qsort(vector<int> & arr, int m, int n) //m - lower limit, n - upper limit
{
if (n - m == 1)
{
return;
}
int p = arr[m], j, t; //p - pivot element, t - temporary
//partition
for (int i = m + 1; i < n; i++)
{
j = i;
if (arr[j] < p)
{
t = arr[j];
while (arr[j] != p)
{
arr[j] = arr[j - 1];
j--;
}
arr[j] = t; //pivot is at j and j+1
}
}
//check if sorted
int f = 1;
while (arr[f] > arr[f - 1])
{
if (f == n - 1)
{
f = -1;
break;
}
f++;
}
if (f == -1)
{
cout << "Sub Array Sorted\n";
}
else
{
if (p == arr[m]) //pivot is the smallest in sub array
{
qsort(arr, m + 1, n); //sort right sub array
}
else
{
qsort(arr, m, j + 1); //sort left sub array
qsort(arr, j + 1, n); //sort right sub array
}
}
}
int main()
{
vector<int> arr = { 4,3,7,1,6,4 };
qsort(arr, 0, arr.size());
for (unsigned int i = 0; i < arr.size(); i++)
{
cout << arr[i] << " ";
}
return 0;
}
答案 1 :(得分:0)
首先,你所做的不是快速排序,而是分裂 - 征服分区和插入排序的某种组合。
Canonical quicksort来自数组的下(p)和上(q)边界,分别跳过元素arr [p] m。然后用arr [q]交换arr [p],递增/递减并检查p> = q。冲洗并重复直至p> = q。然后在子分区上进行调用。这种方式p或q保持枢轴位置和子弹很明显。
但是你的方式不同:你从子阵列的右侧向左侧插入元素。这样的事情可以产生一次迭代的O(N ^ 2)时间复杂度。例如,考虑1,0,1,0,1,0,1,0,1,0,1,0,...序列。这可能会增加O(N ^ 2)的最坏情况复杂性。
时间复杂度...函数中的问题在于假设j在子查询中保存了枢轴位置:
qsort(arr, m, j+1); //sort left sub array
qsort(arr, j+1, n); //sort right sub array
实际上,j在你的main for循环中一次又一次地设置为等于i。如果最后一个元素等于或大于pivot,你最终得到j = n-1,你调用qsort(arr,n,n)并传递第一行检查(sic!),因为nn!= 1。
要解决此问题,您应该做两件事:
1)重新排列后直接找到枢轴位置:
for (int i = m; i < n; i++)
if (p == arr[i])
{
j = i;
break;
}
或在不同变量中初始化,在此行之后更新:
arr[j] = t; //pivot is at j and j+1
并更新递归调用以使用新变量而不是j
2)在你的功能开始时做一个更加防弹的检查:
if (n - m <= 1)
后者足以得到一些结果,但它会比你目前的想法低得多,在最坏的情况下可能会下降到O(N ^ 3)。