Quick Select Algorithm - c++

Im trying to implement the Quick Select Algorithm on a Array that has randomly generated numbers. Now after writing the algorithm in code, it does not sort the array from lowest to highest nor am i able to find the kth smallest element. I would appreciate the help i get. Thank you.
#include<iostream>
#include<ctime>
#include<cstdlib>
using namespace std;
void printArray(int *myArray, int n){
for(int i = 0; i < n; i++){
cout << myArray[i] << " ";
}
}
int Partition(int *myArray, int startingIndex, int endingIndex){
int pivot = myArray[endingIndex];
int partitionIndex = startingIndex;
for(int i = startingIndex; i<endingIndex; i++){
if(myArray[i]<= pivot){
swap(myArray[i],myArray[partitionIndex]);
partitionIndex++;
}
}
swap(myArray[partitionIndex],myArray[endingIndex]);
return partitionIndex;
}
int QuickSelect(int *myArray, int startingIndex, int endingIndex, int KthElement){
/*if(startingIndex < endingIndex){
int partitionIndex = Partition(myArray, startingIndex,endingIndex);
QuickSelect(myArray,startingIndex,partitionIndex-1);
QuickSelect(myArray,partitionIndex+1,endingIndex);
}*/1
if (startingIndex < endingIndex){
int partitionIndex = Partition(myArray, startingIndex, endingIndex);
if(KthElement == partitionIndex)
return KthElement;
if(KthElement < partitionIndex)
QuickSelect(myArray, startingIndex, partitionIndex - 1, KthElement);
else
QuickSelect(myArray, partitionIndex + 1, endingIndex, KthElement);
}
}
int main(){
int numOfElements;
int KthElement;
srand(time(NULL));
cout<<"Enter The Amount Of Numbers You Wish To Use: ";
cin >> numOfElements;
int myArray[numOfElements];
cout << "Array Before Sorting: ";
for(int i = 0; i< numOfElements; i++){
myArray[i] = rand() %10;
}
printArray(myArray, numOfElements);
cout << endl;
cout << endl;
cout <<"Enter The Index Of The Kth Element You Wish To Retrieve: ";
cin >> KthElement;
QuickSelect(myArray, 0,numOfElements,KthElement);
cout << "Array After Sorting: ";
printArray(myArray, numOfElements);
cout << endl;
cout <<"The " <<KthElement<<" Smallest Element Is: " << QuickSelect(myArray,0,numOfElements,KthElement);
}

For numOfElements as 5, array extends from 0 to 4.
Your endingIndex assumes that its the last index of the array.
Fix:
QuickSelect(myArray, 0,numOfElements-1,KthElement);
Problems with your code:
Your program accesses out of bound array locations in
int pivot = myArray[endingIndex];
Have a check for k<1 and k>(num_of_elements).
Check your code for num_of_elements = 1 as well.
Check what k means for the array, i.e For k=1 , arr[0] should be returned not arr[1];

Related

How to write partition for quicksort with C++

I am writing an algorithm in C++ where the user types how many numbers they want to be sorted, then the program generates an array of random numbers, and sorts them. It also displays how much time it took to sort.
It only works for some of the trials, even if I use the same input. For example, if I ask the program to sort an array of 20 numbers, one of three things will happen:
It will sort the array with no problems.
The algorithm will time out and the terminal will print "Segmentation fault: 11".
The algorithm will sort the numbers in the correct order, but one number will be replaced with a random negative number.
Here is my partition algorithm (the thing giving me trouble). I am choosing the first/left item as my pivot:
int partition(int arr[], int leftIndex, int rightIndex)
{
int i = leftIndex;
int j = rightIndex;
int pivotValue = arr[leftIndex];
while(i < j){
while(arr[i] <= pivotValue){
i++;
}
while(arr[j] > pivotValue && i < j){
j--;
}
if(i < j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i - 1];
arr[i - 1] = arr[leftIndex];
arr[leftIndex] = temp;
return i - 1;
}
Here is my quicksort algorithm:
void quickSort(int arr[], int left, int right)
{
if (left < right)
{
int pivot = partition(arr, left, right);
quickSort(arr, left, pivot - 1);
quickSort(arr, pivot + 1, right);
}
return;
}
Here is where I call everything in main():
int main()
{
clock_t sTime, eTime;
int n;
cout << "Enter an array size: " << endl;
cin >> n;
cout << endl;
int originalArray[n];
cout << "Start generating random numbers..." << endl;
for(int index=0; index<n; index++){
originalArray[index] = (rand()%100)+1;
}
cout << "Original array values: ";
printArray(originalArray, n);
cout<<"\n\n";
//Makes a copy of the original array to preserve its original order
int quickArray[sizeof(originalArray)];
for(int i = 0; i < sizeof(originalArray); i++){
quickArray[i] = originalArray[i];
}
//Perform quicksort
sTime = clock();
quickSort(quickArray, 0, n-1);
eTime = clock();
printf("Sorted array by quickSort: ");
printArray(quickArray, n);
cout << "\nTotal CPU time used in quickSort: " << (double)(eTime-sTime) / CLOCKS_PER_SEC * 1000.0 << " ms" << endl;
cout << endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int partition(int arr[], int leftIndex, int rightIndex)
{
int pivotIndex = leftIndex;
int pivotValue = arr[pivotIndex];
int i = leftIndex;
int j = rightIndex;
while(i < j){
while(arr[i] <= pivotValue){
i++;
if(i >= rightIndex) break;
}
while(arr[j] >= pivotValue){
j--;
if(j <= leftIndex) break;
}
if(i < j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// swap
arr[pivotIndex] = arr[j];
arr[j] = pivotValue;
return j;
}
void quickSort(int arr[], int left, int right)
{
if (left < right)
{
int pivot = partition(arr, left, right);
quickSort(arr, left, pivot - 1);
quickSort(arr, pivot + 1, right);
}
return;
}
int main()
{
clock_t sTime, eTime;
int n;
cout << "Enter an array size: " << endl;
cin >> n;
cout << endl;
int originalArray[n];
cout << "Start generating random numbers..." << endl;
for(int index=0; index<n; index++){
originalArray[index] = (rand()%100)+1;
}
cout << "Original array values: ";
for(auto c: originalArray) {
cout << c << " ";
}
cout<<"\n\n";
//Makes a copy of the original array to preserve its original order
int quickArray[n];
for(int i = 0; i < n; i++){
quickArray[i] = originalArray[i];
}
//Perform quicksort
sTime = clock();
quickSort(quickArray, 0, n-1);
eTime = clock();
printf("Sorted array by quickSort: ");
for(auto c: quickArray) {
cout << c << " ";
}
cout << endl;
cout << "\nTotal CPU time used in quickSort: " << (double)(eTime-sTime) / CLOCKS_PER_SEC * 1000.0 << " ms" << endl;
cout << endl;
return 0;
}
There were several mistakes I've encountered. Firstly, I have added break statements in the while loops of partititon() method so that it breaks incrementing i or decrementing j if they exceeds the boundaries of the array. That was probably why you get segmentation fault sometimes.
Then I've changed the swapping part at the end of the partition and returned j. Probably this part was not erroneous, but I find this solution to be more readable.
Then I changed the part where you create the new array to int quickArray[n], you were creating the quickArray with sizeof(originalArray), which was wrong because it used to create an array with more elements. sizeof() returns (number of elements) * 4 since each int takes 4 bytes of memory.
Now, it should be working properly.
In addition, picking the first element as pivot can make your program work in O(n^2) time complexity in the worst case, try shuffling your array before sending it to the quicksort() function. By doing so, you can eliminate the worst case scenario.
I'm not sure if it's responsible for all the problems you're seeing, but I'd start with this bit of code:
while(i < j){
while(arr[i] <= pivotValue){
i++;
}
What's this (especially the inner loop) going to do if the pivot is the largest value in the array?

Shift array elements

I need some help, I know this question was asked before but I don't get it and I cant solve it, so I need help. I need to move the elements of my array to a position to left. So if the input will be 1,2,3,4,5 then the output will be 2,3,4,5,1. I have done the same to right but to left I cant figure it out, please also explain the logic , thanks.
#include <iostream>
using namespace std;
int a[100],n,i,tempr,templ;
int main()
{
cin>>n;
for(i=1;i<=n;i++) cin >> a[i];
for(i=1;i<=n;i++)
{
tempr = a[n];
a[n] = a[i];
a[i] = tempr;
cout<<"Right: "<<a[i]<<endl;
}
for(i=1;i<=n;i++)
{
templ = a[2];
a[2] = a[i];
a[i] = templ;
cout<<"Left: "<<a[i]<<endl;
}
return 0;
}
Please help!
First problem is bad indexing:
for(i=1;i<=n;i++) cin >> a[i]; //wrong logic, C++ indexing start from 0
Correct approach:
for(i=0;i<n;i++) //all your loops
Second problem is wrong logic for shifting elements:
Corrected version:
//input example: 1 2 3 4 5
//to the left
int temp = a[0]; //remember first element
for(i=0;i<n-1;i++)
{
a[i] = a[i+1]; //move all element to the left except first one
}
a[n-1] = temp; //assign remembered value to last element
//output: 2 3 4 5 1
cout << "To left: " << endl;
for(i=0;i<n;i++)
cout << a[i] << endl;
//to the right
temp = a[n-1]; //remember last element
for(i=n-1;i>=0;i--)
{
a[i+1] = a[i]; //move all element to the right except last one
}
a[0] = temp; //assign remembered value to first element
//output: 1 2 3 4 5 because elements are shifted back by right shift
cout << "To right: " << endl;
for(i=0;i<n;i++)
cout << a[i] << endl;
EDIT:
How to display both shifts:
#include <iostream>
using namespace std;
int to_left[5], to_right[5],n,i,tempr,templ;
int main()
{
cout << "Input array size: ";
cin >> n;
for(i=0;i<n;i++)
{
cin >> to_left[i]; //read values to first array
to_right[i]=to_left[i]; //then copy values to second one
}
//shift first array to left
int temp = to_left[0];
for(i=0;i<n-1;i++)
{
to_left[i] = to_left[i+1]; //move all element to the left except first one
}
to_left[n-1] = temp; //assign remembered value to last element
//output: 2 3 4 5 1
cout << "To left: " << endl;
for(i=0;i<n;i++)
cout << to_left[i] << endl;
//shift second array to right
temp = to_right[n-1]; //remember last element
for(i=n-1;i>=0;i--)
{
to_right[i+1] = to_right[i]; //move all element to the right except last one
}
to_right[0] = temp; //assign remembered value to first element
//output: 1 2 3 4 5 because elements are shifted back by right shift
cout << "To right: " << endl;
for(i=0;i<n;i++)
cout << to_right[i] << endl;
return 0;
}
Note that your code look very much like C code. In C++, you can declare variables in any segment of code, not just at the beginning. In C++, you can declare variable in for loop like this: for(int i=0; i<...) - no need for global variable i
For reference, this would be good C++ code example that satisfies problem you are facing:
#include <iostream>
#include <vector>
int main()
{
std::size_t n; //size_t is unsiged type used for various sizes of containers or types
std::cout << "Input array size: ";
std::cin >> n;
std::vector<int> to_left(n), to_right(n); //two dynamic arrays containing integers, takin n as their size
for(std::size_t i=0;i<to_left.size();++i) //use vector size(), instead of n, also ++i in considered better for loops that i++ (may be faster)
{
std::cin >> to_left[i];
to_right[i]=to_left[i];
}
int temp = to_left[0]; //declare temp here, not at the begining of code
for(std::size_t i=0;i<n-1;++i)
to_left[i] = to_left[i+1];
to_left[n-1] = temp;
std::cout << "To left: " << std::endl;
for(std::size_t i=0;i<n;++i)
std::cout << to_left[i] << std::endl;
temp = to_right[n-1]; //reuse temp
for(int i=to_right.size()-1;i>=0;--i) //note int, not std::size_t, because size_t is always >=0, loop would never end.
to_right[i+1] = to_right[i];
to_right[0] = temp;
std::cout << "To right: " << std::endl;
for(std::size_t i=0;i<n;i++)
std::cout << to_right[i] << std::endl;
return 0;
}
And here would be ideal C++ code:
#include <iostream>
#include <vector>
#include <algorithm>
int main()
{
std::size_t n;
std::cout << "Input array size: ";
std::cin >> n;
std::vector<int> to_left(n), to_right(n);
for(std::size_t i=0;i<to_left.size();++i)
{
std::cin >> to_left[i];
to_right[i]=to_left[i];
}
// rotate first array to the left
std::rotate(to_left.begin(), to_left.begin() + 1, to_left.end());
// rotate second array to right
std::rotate(to_right.rbegin(), to_right.rbegin() + 1, to_right.rend());
std::cout << "To left:" << std::endl;
for(auto x : to_left) //C++11 feature, x iterates through container
std::cout << x << std::endl;
std::cout << "To right:" << std::endl;
for(auto x : to_right)
std::cout << x << std::endl;
return 0;
}
Or you can use memmove(...) projected exactly for those purpose, here your sample:
#include <iostream>
#include <cstring>
using namespace std;
//rotate Left
void r_left(int *a,int n)
{
int tmp=a[0];
memmove(a,a+1,sizeof(int)*(n-1));
a[n-1]=tmp;
}
//rotate right
void r_right(int *a,int n)
{
int tmp=a[n-1];
memmove(a+1,a,sizeof(int)*(n-1));
a[0]=tmp;
}
void show(int *a,int n)
{
while(n--)
cout<<*a++<<' ';
cout<<endl;
}
int main()
{
int ar[]={1,2,3,4,5};
int n=sizeof(ar)/sizeof(ar[0]);
r_left(ar,n);
show(ar,n);
r_right(ar,n);
show(ar,n);
return 0;
}
easiest way to swap elements in C++ is to use std::iter_swap()
so for an array of 4 elements to swap elements 1 and 4 you would do the following
int a[4];
std::iter_swap(a, a+3);
note that you also need to #include <algorithm> for this to work
the basic logic of the function is that you give the location in memory of the 2 elements, so as the first element of an array is also its location in memory, you can pass a + n, when n is equal to the n-1 index number of the element you want to swap
As other already have stated it's all about indices. In a for-loop you are almost always in trouble if your stop condition is i <= size, because arrays in C++ are zero-indexed.
Where Black Moses alogrithm is far the easiest to understand (and probably the fastes), I read your code as if you try to swap the first value of the array through the array to the last position. Below I have tried to pin out this approach.
#include <stdio.h>
#include <tchar.h>
#include <iostream>
void ShiftLeft(int* pArr, size_t length)
{
for (size_t i = 1; i < length; i++)
{
int tmp = pArr[i - 1]; // Preserves the previous value
pArr[i - 1] = pArr[i]; // Overwrites the previous position with the current value
pArr[i] = tmp; // Stores the previous value in the current position
// All in all the first value is swapped down the array until it is at the length - 1 position
// and all the other values are swapped to the left.
/* For an array with 4 values the progression is as follows:
i = 0: 1 2 3 4
i = 1: 2 1 3 4
i = 2: 2 3 1 4
i = 3: 2 3 4 1
*/
}
}
void ShiftRight(int* pArr, size_t length)
{
for (size_t i = length - 1; i > 0; i--)
{
// This code does exactly the same as for ShiftLeft but the loop is running backwards
int tmp = pArr[i - 1];
pArr[i - 1] = pArr[i];
pArr[i] = tmp;
}
}
void Print(int* pArr, size_t length)
{
for (size_t i = 0; i < length; i++)
{
std::cout << pArr[i] << " ";
}
std::cout << std::endl;
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6 };
size_t length = sizeof(arr) / sizeof(arr[0]);
Print(arr, length);
ShiftLeft(arr, length);
Print(arr, length);
ShiftRight(arr, length);
Print(arr, length);
return 0;
}
#include <iostream>
using namespace std;
int a[100], outR[100], outL[100], n, i;
int main() {
cin >> n;
for (i = 0; i < n; i++) cin >> a[i];
// Right
for (i = 0; i < n; i++) {
outR[i+1]= a[i];
}
outR[0] = a[n-1]; // add first number
// Left
for (i = 1; i < n; i++) {
outL[i-1]= a[i];
}
outL[n-1] = a[0]; // add last number
// Answer
cout << "Right:\n";
for(i=0; i<n; i++) {
cout << outR[i] << endl;
}
cout << "Left:\n";
for(i = 0; i < n; i++) {
cout << outL[i] << endl;
}
return 0;
}
Simple answer where you can easily see everything, good luck.
You may be interested in ,,vector coding", it seems be easier if you spend some time on this:
#include <iostream>
#include <vector>
using namespace std;
vector <int> a, outR, outL;
size_t i;
int main () {
int n, temp_int;
cin >> n;
while (n--) {
cin >> temp_int; // here you read number to your vector
a.push_back(temp_int); // here you add this to vector
// remember that vector start from element 0 as like arrays
}
// Left
// remember that last element will be first
// you may have acces to size of your vector easily
for (i = 0; i < (a.size()-1); i++) {
outL.push_back(a.at(i+1)); // here you create new vector
}
outL.push_back(a.at(0)); // add last elemet which rotated
// Right
// to rotate left first you have push last element so
outR.push_back(a.at(a.size()-1)); // add first elemet which rotated
for (i = 1; i < a.size(); i++) {
outR.push_back(a.at(i-1)); // here you push rest
}
cout << "Left" << "\n";
for (i = 0; i < a.size(); i++) {
cout << outL.at(i) << endl; // here you print value
}
cout << "Right" << "\n";
for (i = 0; i < a.size(); i++) {
cout << outR.at(i) << endl; // here you print value
}
return 0;
}
int* leftShiftOneByOneWIthoutTemp(int arr[], int sz)
{
for (int i=0 ;i < sz-1; i++)
{
arr[i] = arr[sz-1] + arr[i];
arr[sz-1] = arr[i] - arr[sz-1] ;
arr[i] = arr[i] - arr[sz-1] ;
std::cout << "iter "<< i << std::endl;
printArray(arr,5);
}
std::cout << "final "<< std::endl;
printArray(arr,5);
return arr;
}
Replace your code (to shift array left) with below code.
templ = a[0];
for(i=0;i<n-1;i++)
{
a[i] = a[i+1];
cout<<"Left: "<<a[i]<<endl;
}
a[n-1] = templ;
cout<<"Left: "<<a[n-1]<<endl;

C++ Vector Subscript Issues

I was making an app that calculates the mean, median, and range of any integers, but I ran into the issue: Vector subscript out of range. I've looked at some other posts about this, and still haven't been able to fix it.
Here's my code:
#include <iostream>
#include <Algorithm>
#include <Windows.h>
#include <vector>
using namespace std;
int main() {
//Variables
int sze;
int mraw = 0;
double mean;
double median;
double range;
int fullnum = 0;
int lastnum = 1;
vector<int> med;
cout << "How many numbers do you have? ";
cin >> sze;
int *arr = new int[sze];
for (int i = 0; i < sze; i++) {
med.push_back(arr[i]);
}
//Getting numbers
for (int i = 0; i < sze, i++;) {
system("cls");
cout << "Enter number #" << i + 1 << ": ";
cin >> arr[i];
}
//Mean
for (int i = 0; i < sze; i++){
fullnum += arr[i];
}
mean = fullnum / sze;
//Median
sort(med.begin(), med.end());
int mvs = sze;
while (med.size() >= 2) {
med.erase(med.begin());
med.erase(med.begin() + med.size() - 1);
mvs--;
}
if (mvs == 2) {
mraw = med[1] + med[2];
median = mraw / 2;
}
else {
median = mvs;
}
//Range
vector<int> rnge;
for (int i = 0; i < sze; i++) {
rnge.push_back(arr[i]);
lastnum++;
}
sort(rnge.begin(), rnge.end());
int bigsmall[2];
bigsmall[1] = rnge[1];
bigsmall[2] = rnge[lastnum];
range = bigsmall[2] - bigsmall[1];
//Outputs
cout << "Mean: " << mean << "\nMedian: " << median << "\nRange: " << range;
system("cls");
return 0;
}
You have what would be an off-by-one error if lastnum was initialized to 0.
When rnge is empty, presumably lastnum is 0. This means access rnge[lastnum] is in error, as rnge is empty.
Applying an inductive argument shows that lastnum is the count of number of elements, and not the index of the last element. Thus, rnge[lastnum] is always out of range.
In actuality, you have initialized lastnum to 1, so your bug is actually off-by-two.

Sorting through array of pointers

When I try to display the test scores in the function sortArray, I can only access the memory address. How to I access the values of the scores?? Also is the sortArray function correct overall?
#include <iostream>
using namespace std;
void sortArray(int *[], int);
int main()
{
int *testScores = nullptr;
//dynamically allocate an array
int scoreNUMS;
int score;
cout << "Please enter the total number of test scores" << endl;
cin >> scoreNUMS;
testScores = new int[scoreNUMS];
//dynamically allocates an array large enough to hold scoreNUMS
for(int i = 1; i <= scoreNUMS; i++)
{
cout << "Enter student " << i << "'s test score" << endl;
cin >> score;
if (score <= -1)
{
cout << "Please enter positive numbers only!" << endl;
}
*(testScores + i) = score;
//puts the input score in the array
}
sortArray(&testScores, scoreNUMS);
return 0;
}
Im not sure if the function below is correct because I was unaware where to place the * and the &
void sortArray(int *array[], int size)
{
bool swap;
int temp;
do
{
swap = false;
for(int count = 0;count < (size - 1); count++)
{
if(array[count] > array[count + 1])
{
temp = *array[count];
array[count] = array[count + 1];
array[count + 1] = &temp;
swap = true;
}
}
}while(swap);
for(int i = 0; i < size; i++)
cout << *(array + 1) << endl;
}
Error: Array consist scoreNUMS elements, the first one is testScores[0] - first index is zero. And last index is scoreNUMS-1
You must write
for(int i = 0; i < scoreNUMS; i++)
PS: You can use next prototype:
void sortArray(int [], int);
UPD: passing an array to a function is performed by passing a pointer to the first element of the array. (Your array does not copied when you pass it to function)
And run function by this way: sortArray(testScores, scoreNUMS);

C++ max of an array using recursion issue

I have this program that finds the largest integer in an array using recursion, but it keeps returning the last number entered no matter what the value instead of the largest number. How do i fix this?
#include <iostream>
using namespace std;
int maximum(int digits[], int size, int largest, int i);
void main()
{
const int size = 3;
int digits[size];
int n = 0, x = 0;
for(int a = 0; a < size; a++)
{
cout << "Enter an integer <" << ++x << " out of " << size << ">: ";
cin >> digits[n];
}
cout << "\nThe largest digit is, " << maximum(digits, size, 0, 0) << ", thank you!\n";
cout << endl;
}
int maximum(int digits[], int size, int largest, int i)
{
if ( i < size )
{
if ( largest < digits[i])
largest = digits[i];
maximum( digits, size, largest, i + 1);
}
return largest;
}
First use the index variable properly in main()
for(int a = 0; a < size; a++)
{
cout << "Enter an integer <" << ++x << " out of " << size << ">: ";
cin >> digits[a];//-->Use the index varible correctly.
}
int maximum(int digits[], int size, int largest, int i)
{
if(i==size-1)
return digits[i]; //The base case is specified here.
if ( i < size )
{
int temp= maximum( digits, size, largest, i + 1);
if ( digits[i] < temp)
largest =temp;
else
largest=digits[i];
}
return largest;
}
Please check out the changes. Carefully read the code. You will understand your mistakes.
When designing recursion think of few things first-
The base condition. (This stops the recursion).
The recursive step. (Where you will calculate something based on previous calculation)
Combine step- You have to combine them (value at this stage and value got from recusive step) to get the correct answer. This step is not required in some cases.
It should be return maximum( digits, size, largest, i + 1);
Live example.
int biggestOne(int integerArray[], int lengthOfArray, int max)
{
if (lengthOfArray==0) return max;
if (max < integerArray[lengthOfArray-1]) max = integerArray[lengthOfArray-1];
return biggestOne(integerArray,lengthOfArray-1,max);
}
int main()
{
int array[] = {7,2,9,10,1};
int arrSize = sizeof(array)/sizeof(array[0]); //returns length of the array
cout <<"Biggest number in the array: " << biggestOne(array,arrSize,0) << endl;
return 0;
}