For some reason, whenever I try to compile the program it says "File has stopped working". It doesn't give any specific errors so I have no clue what is wrong. I've looked it over many times and can't find any errors.
This is an implementation of a quicksort algorithm.
int partition(int arr[], int left, int right) {
int pivotPos = left + rand() % right;
int pivot = arr[pivotPos];
int p = left;
swap(arr[pivotPos], arr[right]);
for (int i = left; i < right; i++) {
if (arr[i] <= pivot) {
swap(arr[i], arr[p]);
p++;
}
}
swap(arr[p], arr[pivotPos]);
return p;
}
void quickSort(int arr[], int left, int right) {
if (left < right) {
int partitionIndex = partition(arr, left, right);
quickSort(arr, left, partitionIndex - 1);
quickSort(arr, partitionIndex + 1, right);
}
}
int main() {
int theArr[10000];
clock_t d1, d2;
for (int i = 0; i < 10000; i++) {
theArr[i] = 1 + rand() % 500;
}
for (int i = 0; i < 10; i++) {
d1 = clock();
quickSort(theArr, 0, 10000);
d2 = clock();
cout << "Time: " << ((double) (d2 - d1) / (CLOCKS_PER_SEC)) << endl;
}
return 0;
}
As hvd pointed out in the comments section, the following line appears wrong.
int pivotPos = left + rand() % right;
What you are looking for is:
int pivotPos = left + rand() % (right-left);
I do not understand why do you are swapping arr[p] and arr[pivotPos] after the loop has ended.
pivotPos is the initial location of the pivot. The final location of the pivot will be p-1. At the end of the loop the array is already arranged as required. This swapping will only make the array more haphazard. And therefore, in addition to replacing
int pivotPos = left + rand() % right;
by
int pivotPos = left + rand() % (right - left);
and replacing
arr[right] by arr[right-1]
You should also replace
swap(arr[p], arr[pivotPos]);
return p;
by
return p-1;
And, since the third argument of the function quickSort is <maximum index> + 1, the recursive call
quickSort(arr, left, partitionIndex - 1);
should be replaced by
quickSort(arr, left, partitionIndex);
Related
I tried to implement merge sort using C++, however, something went wrong. I have no idea what is wrong.
The following code is what I wrote based on CLRS. I think it is quite easy to understand the meaning.
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int>& nums, int p, int q, int r);
void mergeSort(vector<int>& nums, int p, int r){
if (p < r) {
int q = (p + r) / 2;
mergeSort(nums, p, q);
mergeSort(nums, q + 1, r);
merge(nums, p, q, r);
}
}
void merge(vector<int>& nums, int p, int q, int r) {
int s1 = p, s2 = q + 1;
vector<int> l1, l2;
for (int i = s1; i <= q; i++) {
l1.push_back(nums[i]);
}
for (int i = s2; i <= r; i++) {
l2.push_back(nums[i]);
}
int left = 0, right = 0;
int idx = 0;
while (left < l1.size() && right < l2.size()) {
if (l1[left] < l2[right]) {
nums[idx] = l1[left++];
}
else {
nums[idx] = l2[right++];
}
idx++;
}
while (left < l1.size()) {
nums[idx++] = l1[left++];
}
while (right < l2.size()) {
nums[idx++] = l2[right++];
}
}
int main() {
vector<int> vect;
vect.push_back(1);
vect.push_back(3);
vect.push_back(12);
vect.push_back(23);
vect.push_back(4);
vect.push_back(11);
vect.push_back(44);
vect.push_back(322);
mergeSort(vect, 0, vect.size() - 1);
for (int i = 0; i < vect.size(); i++) {
cout << vect[i] << endl;
}
return 0;
}
I want to use the program to sort some integers, however, it only shows many duplicate numbers. What's going on? I don't think there is a problem of the merge function.
The code needs a one line fix:
int idx = p; // not idx = 0
Optimized top down using arrays from Wiki article (note bottom up is slightly faster):
void TopDownMerge(int A[], int bgn, int mid, int end, int B[])
{
int i, j, k;
i = bgn, j = mid, k = bgn;
while(1){
if(A[i] <= A[j]){ // if left smaller
B[k++] = A[i++]; // copy left element
if(i < mid) // if not end of left run
continue; // continue
do // else copy rest of right run
B[k++] = A[j++];
while(j < end);
break; // and break
} else { // else right smaller
B[k++] = A[j++]; // copy right element
if(j < end) // if not end of right run
continue; // continue
do // else copy rest of left run
B[k++] = A[i++];
while(i < mid);
break; // and break
}
}
}
void TopDownSplitMerge(int B[], int bgn, int end, int A[])
{
if (end - bgn <= 1) // if run size == 1
return; // consider it sorted
int mid = (end + bgn) / 2;
TopDownSplitMerge(A, bgn, mid, B);
TopDownSplitMerge(A, mid, end, B);
TopDownMerge(B, bgn, mid, end, A);
}
void TopDownMergeSort(int A[], int n) // n = size (not size-1)
{
if(n < 2)
return;
int *B = new int [n]; // 1 time allocate and copy
for(size_t i = 0; i < n; i++)
B[i] = A[i];
TopDownSplitMerge(B, 0, n, A); // sort data from B[] into A[]
delete B;
}
Afterwards, I finally get to fix the bugs of my program. After modification, here is the code:
class Solution {
public:
vector<int> temp;
vector<int> sortArray(vector<int>& nums) {
temp.resize((int)nums.size(), 0);
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
void mergeSort(vector<int>& nums, int start, int end) {
if (start >= end) return;
int middle = (start + end) / 2;
mergeSort(nums, start, middle);
mergeSort(nums, middle + 1, end);
merge(nums, start, middle, end);
}
void merge(vector<int>& nums, int leftStart, int middle, int rightEnd) {
int leftEnd = middle;
int rightStart = middle + 1;
int i = leftStart, j = rightStart;
int index = 0;
while (i <= leftEnd && j <= rightEnd) {
if (nums[i] < nums[j]) {
temp[index] = nums[i++];
}
else {
temp[index] = nums[j++];
}
index++;
}
while (i <= leftEnd) {
temp[index++] = nums[i++];
}
while (j <= rightEnd) {
temp[index++] = nums[j++];
}
for (int i = 0; i < rightEnd - leftStart + 1; i++) {
nums[i + leftStart] = temp[i];
}
}
};
Here is something should be careful next time:
In the merge part, it is difficult to merge in place. It'd be better to use another temp array to store the merged results and update to the target array (nums in this case).
Readable identifers is very recommended (Although the pseudocode of CLRS may not use that part).
Need to use debuggers to find the bug of program {However, it takes like forever to load local variables of VS Code debugers.
Im working on a homework assignment comparing both execution time and theoretical O-notation of 10 separate sorts. However, as the question says I keep having an infinite loop when I get to the point that the code recursively calls merge sort. I know that it is when the left is at 2 and the right is at 3 so middle continuously returns as 3. is merge supposed to be outside of the if statement? I don't think that would be right either though when I look at it.
void merge(int arr[], int left, int middle, int right)
{
// get the temporary array lengths
int first = middle - left + 1;
int second = right - middle;
// make the temp dynamic arrays
int *Left = new int(first);
int *Right = new int(second);
for (int i = 0; i < first; i++)
{
Left[i] = arr[left + i];
}
for (int i = 0; i < second; i++)
{
Right[i] = arr[middle + 1 + i];
}
// merge the arrays back into arr
int i = 0;
int j = 0;
int k = left;
while (i < first && j < second)
{
// check which one is bigger
if (Left[i] <= Right[j])
{
arr[k] = Left[i];
i++;
}
else
{
arr[k] = Right[j];
j++;
}
k++;
}
// copy Left remainder
while (i < first)
{
arr[k] = Left[i];
i++;
k++;
}
// copy right remainder
while (j < second)
{
arr[k] = Right[j];
j++;
k++;
}
}
void mergeSort(int arr[], int left, int right)
{
if (left < right)
{
int middle = left + (right - 1) / 2;
mergeSort(arr, left, middle);
mergeSort(arr, middle + 1, right);
merge(arr, left, middle, right);
}
}
In mergeSort function, you forgot parenthesis when calculating middle. It should be:
int middle = (left + (right - 1)) / 2;
Also, in merge function, Left and Right should have type int[]. Instead of new int(SIZE), you should use new int[SIZE]. Moreover, you should use delete[] to delete them before leaving the function to prevent memory leak.
// make the temp dynamic arrays
int* Left = new int[first];
int* Right = new int[second];
// ...
// at the end of the `merge` function
delete[] Left;
delete[] Right;
I can't figure out why this code isn't quite correct. It sorts most of the array, but some numbers are out of place. Any help would be much appreciated.
int partition(int* an_array, int from, int to)
{
int pivot = an_array[(from + to) / 2];
int left = from;
int right = to;
while(left < right)
{
while(an_array[left] < pivot)
{
left = left + 1;
}//end while loop
while(an_array[right] > pivot)
{
right = right - 1;
}//end while
if(left < right)
{
swap_numbers(an_array[left], an_array[right]);
left = left + 1;
right = right - 1;
}//end if
}//end while loop
return right;
}//end partition function
void quick_sort(int* an_array, int from, int to)
{
if(from >= to) return;
int p = partition(an_array, from, to);
quick_sort(an_array, from, p);
quick_sort(an_array, p + 1, to);
}//end quick_sort
You forget to add:
swap_numbers(an_array[from], an_array[right]);
just before
return right;
I am doing my homework, and completed quicksort recursive, however it doesn't sort in a correct way. Seems to be it doesn't swap correctly.
Here is my code
#include<iostream>
#include<ctime>
#include<string>
using namespace std;
int quick_sort_help(string &text,int left, int right, int pivot){
char val = text[pivot];
char temp;
//swap
// temp =text[pivot];
//text[pivot]= text[right];
//text[right]=temp;
//swap(&text[left],&text[right]);
int l = left;
int r = right;
int i=left;
while (i<=r)
{
while (text[i]<val)
i++;
while (text[right]>val)
r--;
if (i<=r)
{
temp=text[i];
text[i]=text[r];
text[r]=temp;
i++;
r--;
}
}
return l;
}
void quicksort(string &text,int left, int right){
if (left < right){
int pivot=(left+right)/2;
int pivottwo = quick_sort_help(text, left, right, pivot);
quicksort(text, left, pivottwo - 1);
quicksort(text, pivottwo + 1, right);
}
}
void quick_sort(string &text,int size){
quicksort(text,0,size);}
int main()
{
string text="this is a test string text,.,!";
int size = text.length();
float t1, t2;
t1 = clock();
quick_sort(text,size);
t2=clock();
cout<<"quicksort Sort: "<<(t2-t1)/CLK_TCK*1000<<" msec\n";
cout<<text<<endl;
system("pause");
return 0;
}
the output I am getting:
hi a e e,g.nii,r!tssssxttttt
You have to:
1) Don't use size but size-1 value
void quick_sort(string &text,int size){
quicksort(text,0,size-1);}
2) Pivot is not (left+right)/2 but it's the value returned by quick_sort_help, and pivottwo is not necessary:
void quicksort(string &text,int left, int right)
{
if (left < right)
{
int pivot = quick_sort_help(text, left, right);
quicksort(text, left, pivot - 1);
quicksort(text, pivot + 1, right);
}
}
3) Test my j value (your r) in the second while and make the exchange before returning the pivot (the i value):
int quick_sort_help(string &text,int left, int right)
{
char val = text[right];
char temp;
int j = right;
int i = left - 1;
while (true)
{
while (text[++i] < val);
while (text[--j] > val) {
if(j == left)
break;
}
if(i >= j)
break;
temp=text[i];
text[i]=text[j];
text[j]=temp;
}
temp=text[i];
text[i]=text[right];
text[right]=temp;
return i;
}
Take a look at this : Quicksort implementation
while (text[right]>val)
r--;
That doesn't seem likely. You're decrementing r, but the condition you test never changes (should depend on r, probably...)
Also
return l;
looks suspicious, since the calling function seem to expect it to be the new position of the pivot, whereas it is the old left.
Another one, you use closed intervals (see why you shouldn't), which means you're accessing the string out-of bounds (which is UB).
I'm not looking to copy a qsort algorithm. I'm practicing writing qsort and this is what I've come up with and I'm interested in what part of my code is wrong. Please don't tell me that this is homework cause I could just use the code in the link below.
Reference: http://xoax.net/comp/sci/algorithms/Lesson4.php
When this runs I get this in the console:
Program loaded.
run
[Switching to process 10738]
Running…
Current language: auto; currently c++
Program received signal: “EXC_ARITHMETIC”.
void myQSort(int min, int max, int* myArray)
{
// Initially find a random pivot
int pivotIndex = rand() % max;
int pivot = myArray[pivotIndex];
int i = 0 , j = max-1;
// Pointer to begining of array and one to the end
int* begin = myArray;
int* end = &myArray[max-1];
// While begin < end
while( begin < end )
{
// Find the lowest bound number to swap
while( *begin < pivot )
{
begin++;
}
while( *end > pivot )
{
// Find the highest bound number to swap
end--;
}
// Do the swap
swap(begin,end);
}
// Partition left
myQSort(0, pivotIndex-1, myArray);
// Partiion right
myQSort(pivotIndex+1,max, myArray);
}
EDIT--
Code for Swap:
void swap(int* num, int* num2)
{
int temp = *num;
*num = *num2;
*num2 = temp;
}
// sort interval [begin, end)
void myQSort(int* begin, int* end)
{
if(end - begin < 2)
return;
int* l = begin;
int* r = end - 1;
// Initially find a random pivot
int* pivot = l + rand() % (r - l + 1);
while(l != r)
{
// Find the lowest bound number to swap
while(*l < *pivot) ++l;
while(*r >= *pivot && l < r) --r;
// Do the swap
if(pivot == l) { pivot = r; }
std::swap(*l, *r);
}
// Here l == r and numbers in the interval [begin, r) are lower and in the interval [l, end) are greater or equal than the pivot
// Move pivot to the position
std::swap(*pivot, *l);
// Sort left
myQSort(begin, l);
// Sort right
myQSort(l + 1, end);
}
You're not using the min parameter in your code, anywhere. You need to set begin and your pivot value using that.
I tried working out the codes above. But, they don't compile.
#Mihran: Your solution is correct algorithmically but the following line generates an error:
myQSort(min, begin - myArray, myArray);
This is because begin is of type int* and myArray is of type long, following which the compiler shows this error message:
implicit conversion loses integer precision
Here's a working solution in C++:
#include <iostream>
using namespace std;
void mySwap(int& num1, int& num2){
int temp = num1;
num1 = num2;
num2 = temp;
}
void myQsort(int myArray[], int min, int max){
int pivot = myArray[(min + max) / 2];
int left = min, right = max;
while (left < right) {
while (myArray[left] < pivot) {
left++;
}
while (myArray[right] > pivot) {
right--;
}
if (left <= right) {
mySwap(myArray[left], myArray[right]);
left++;
right--;
}
}
if (min < right) {
myQsort(myArray, min, right);
}
if (left < max) {
myQsort(myArray, left, max);
}
}
int main()
{
int myArray[] = {1, 12, -5, 260, 7, 14, 3, 7, 2};
int min = 0;
int max = sizeof(myArray) / sizeof(int);
myQsort(myArray, min, max-1);
for (int i = 0; i < max; i++) {
cout<<myArray[i]<<" ";
}
return 0;
}
Here's a clear C++ implementation, for reference:
#include <iostream>
#include <vector>
using namespace std;
int partition(std::vector<int>& arr, int low, int high) {
// set wall index
int wall_index = low;
int curr_index = low;
int pivot_elem = arr[high]; // taking last element as pivot_element
// loop through the entire received arr
for (int i = curr_index; i < high; ++i) {
// if element is less than or equal to pivot_elem
// swap the element with element on the right of the wall
// i.e swap arr[i] with arr[wall_index]
if (arr[i] <= pivot_elem) {
// swap
int temp = arr[wall_index];
arr[wall_index] = arr[i];
arr[i] = temp;
// move the wall one index to the right
wall_index++;
curr_index++;
} else {
// if the element is greater than the pivot_element
// then keep the wall at the same point and do nothing
curr_index++;
}
}
// need to swap the pivot_elem i.e arr[high] with the element right of the wall
int temp = arr[wall_index];
arr[wall_index] = arr[high];
arr[high] = temp;
return wall_index;
}
void quick_sort(std::vector<int>& arr, int low, int high) {
if (low < high) { // element with single arr always have low >= high
int split = partition(arr, low, high);
quick_sort(arr, low, split-1);
quick_sort(arr, split, high);
}
}
int main() {
std::vector<int> data = {6,13,8,4,2,7,16,3,8};
int N = data.size();
quick_sort(data, 0, N-1);
for (int i : data) {
cout << i << " ";
}
return 0;
}
I don't see a clean implementation of Quicksort on SO, so here is my easy to understand implementation
PLEASE DONT USE IN PRODUCTION CODE
This is only for your understanding
// Swap position a with b in an array of integer numbers
void swap(int *numbers, int a, int b){
int temp = numbers[a];
numbers[a] = numbers[b];
numbers[b] = temp;
}
static int partition(int *data, int low, int high) {
int left = low, right = high, pivot = data[low];
while (left < right) {
// Everthing on the left of pivot is lower than the pivot
while ((left <= right) && data[left] <= pivot) // <= is because left is the pivot initially
left++;
// Everything on the right of the pivot is greater than the pivot
while((left <= right) && data[right] > pivot)
right--;
if (left < right)
swap(data, left, right);
}
// Put the pivot in the 'rigthful' place
swap(data, low, right);
return right;
}
// Quicksort
static void quick_sort(int *numbers, int low, int high)
{
if (high > low) {
int p_index = partition(numbers, low, high);
quick_sort(numbers, low , p_index - 1);
quick_sort(numbers, p_index + 1, high);
}
}