Implementing Merge Sort in C++ using Vectors - c++

I wanted to do an implementation of Merge Sort in C++. I didn't look at concrete examples because I wanted to try out for myself. And here is what I came up with using vectors:
int *mergeSort(int *a, int n) {
//some debugging info for me
cout << "Merge Sort called with: ";
for(int i = 0; i < n; i++){
cout << *(a + i) << " ";
}
cout << " and size: " << n << endl;
//base case
if (n == 1) {
return a;
}
//spliting the arrays
vector<int> firstArray(a, a + n/2);
vector<int> secondArray(a + n/2, a + n);
int *firstResultPointer = mergeSort(&(firstArray[0]), firstArray.size());
vector<int> resultFirst(firstResultPointer, firstResultPointer + n/2);
int *secondResultPointer = mergeSort(&(secondArray[0]), secondArray.size());
vector<int>resultSecond(secondResultPointer, secondResultPointer + n / 2);
vector<int> resultArray(n);
int i = 0;
int j = 0;
while (i + j < n) {
//when exit the size of the vector
if(firstArray.size() <= i){
while(j < secondArray.size()){
resultArray[(i + j)] = secondArray[j];
j++;
}
break;
}
else if (secondArray.size() <= j){
while(i < firstArray.size()){
resultArray[(i + j)] = firstArray[i];
i++;
}
break;
}
else {
//normal case merge
if (firstArray[i] < secondArray[j]) {
resultArray[(i + j)] = firstArray[i];
i++;
}
else {
resultArray[(i + j)] = secondArray[j];
j++;
}
}
}
return &(resultArray[0]);
}
a is a pointer to the vector and n is the length of the same vector. I had quite a lot of trouble in the merging because it would leave the vector and start using 0. I think I fixed that based on my debugging. However, when I debug after I get to the lowest level and then starting going back up it just starts jumping all over the place and I cannot follow it. Using cout I printed to see what arguments are passed to the merge sort and they seem to be correct. Can anyone tell me where the problem is?

Related

Knapsack Dynamic Programming - Need help on problem (Roller Coaster Fun)

I recently started learning Dynamic Programming, and am currently trying to solve "Roller Coaster Fun" on Kattis. However, I'm only getting 10/30 test cases (wrong answer on test case 11), and am stuck on what I am doing wrong.
My thinking is very similar to the coin problem (7.1 in the CPH, scroll down to "Coin Problem"), where we find the answer for each of the 25,000 times using the previous ones:
(this is pseudocode)
// fun[i] is the maximum amount of fun possible at time i
// k[i][j] is the number of times Jimmy goes on coaster j at time i
// all other functions/variables are as given in the problem
fun[1] = 0
fun[n] = max(fun[n - 1], // last fun value (don't go on any new ride)
fun[n - t[0]] + f(0, k[n][0]),
...,
fun[n - t[i]] + f(i, k[n][i]),
...,
fun[n - t[N - 1]] + f(N - 1, k[n][N - 1]))
Here is my full code:
// https://open.kattis.com/problems/rollercoasterfun
#include <bits/stdc++.h>
using namespace std;
#define MAX_N 100
#define MAX_T 25000
vector<int> a(MAX_N), b(MAX_N), t(MAX_N);
vector<int> dp(MAX_T + 1);
vector<vector<int>> k(MAX_T + 1, vector<int>(MAX_N));
int f(int time, int i)
{
return max(0, a[i] - k[time][i] * k[time][i] * b[i]);
}
int main()
{
int N;
cin >> N;
for (int i = 0; i < N; ++i)
cin >> a[i] >> b[i] >> t[i];
dp[0] = 0;
fill(k[0].begin(), k[0].end(), 0);
for (int time = 1; time <= MAX_T; ++time)
{
dp[time] = dp[time - 1];
k[time] = k[time - 1];
for (int i = 0; i < N; ++i)
{
if (time - t[i] >= 0)
{
int newFun = dp[time - t[i]] + f(time - t[i], i);
if (newFun > dp[time])
{
dp[time] = newFun;
k[time] = k[time - t[i]];
++k[time][i]; // go on this ride one more time
}
}
}
// cout << time << ' ' << dp[time] << '\n';
}
int Q;
cin >> Q;
int q;
for (int i = 0; i < Q; ++i)
{
cin >> q;
cout << dp[q] << '\n';
}
return 0;
}
Any help would be appreciated!

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?

C++ 3sum complexity

I was trying to solve the 3 sum problem in cpp.
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int size = nums.size();
vector<vector<int>> result;
for (int i = 0; i < size - 2; ++i) {
for (int j = i + 1; j < size - 1; ++j) {
for (int k = j + 1; k < size; ++k) {
if (sumToZero(i, j, k, nums)) {
vector<int> newComb = vectorify(i, j, k, nums);
//printComb(newComb);
if (!exist(newComb, result)) {
//cout << "not exist" << endl;
result.push_back(newComb);
} else {
//cout << "exist" << endl;
}
}
}
}
}
return result;
}
bool sumToZero(int i, int j, int k, vector<int>& nums) {
return nums[i] + nums[j] + nums[k] == 0;
}
vector<int> vectorify(int i, int j, int k, vector<int>& nums) {
vector<int> result;
result.push_back(nums[i]);
result.push_back(nums[j]);
result.push_back(nums[k]);
return result;
}
void printComb(vector<int>& input) {
cout << input[0] << input[1] << input[2] << endl;
}
bool isSameComb(vector<int>& a, vector<int> b) {
for (int i = 0; i < b.size(); ++i) {
if (a[0] == b[i]) {
b.erase(b.begin() + i);
}
}
for (int i = 0; i < b.size(); ++i) {
if (a[1] == b[i]) {
b.erase(b.begin() + i);
}
}
for (int i = 0; i < b.size(); ++i) {
if (a[2] == b[i]) {
b.erase(b.begin() + i);
}
}
return b.empty();
}
bool exist(vector<int>& niddle, vector<vector<int>>& haystack) {
int size = haystack.size();
for (int i = 0; i < size; ++i) {
if (isSameComb(niddle, haystack[i])) {
return true;
}
}
return false;
}
};
However, this solution exceeded the time limit. I cannot think of the source of extra complexity. Can someone help me point out where am I doing extra computation?
You can be in O(n²) with something like:
std::vector<std::vector<int>> threeSum(std::vector<int>& nums) {
std::sort(nums.begin(), nums.end());
std::vector<std::vector<int>> res;
for (auto it = nums.begin(); it != nums.end(); ++it) {
auto left = it + 1;
auto right = nums.rbegin();
while (left < right.base()) {
auto sum = *it + *left + *right;
if (sum < 0) {
++left;
} else if (sum > 0) {
++right;
} else {
res.push_back({*it, *left, *right});
std::cout << *it << " " << *left << " " << *right << std::endl;
++left;
++right;
}
}
}
return res;
}
Demo
I let duplicate handling as exercise.
The source of extra complexity is the third loop, which brings time complexity of your code to O(n3).
Key observation here is that once you have two numbers, the third number is fixed, so you do not need to loop around to find it: use hash table to see if it's there or not in O(1). For example, if your first loop looks at value 56 and your second loop looks at value -96, the third value must be 40 in order to yield zero total.
If the range of numbers is reasonably small (say, -10000..10000) you can use an array instead.
This would bring time complexity to O(n2), which should be a noticeable improvement on timing.
A couple of possibilities:
First, construct a hash table of all entries in the vector up front, then remove the third loop. Inside the second loop, simply check whether -nums[i] - nums[j] exists in the hash table. That should bring your time complexity from O(n3) back to something closer to O(n2).
Second, function calls aren't free though an optimiser can sometimes improve that considerably. There's no performance reason why you should be calling a function to check if three numbers add to zero so you could replace:
if (sumToZero(i, j, k, nums)) {
with:
if (nums[i] + nums[j] == -nums[k]) {
Of course, this is rendered moot if you adopt the first suggestion.
Third, don't check and insert the possible result every time you get one. Just add it to the vector no matter what. Then, at the end, sort the vector and remove any duplicates. That should hopefully speed things up a bit as well.
Fourth, there's quite possibly a performance hit for using a vector for the potential result when an int[3] would do just as well. Vectors are ideal if you need something with a variable size but, if both the minimum and maximum size of an array-type collection is always going to be a fixed value, raw arrays are fine.
But perhaps the most important advice is measure, don't guess!
Make sure that, after each attempted optimisation, you test to see whether it had a detrimental, negligible, or beneficial effect. A test suite of various data sets, and automating the process, will make this much easier. But, even if you have to do it manually, do so - you can't improve what you can't measure.
Here is my solution that finds all unique triplets in O(n^2) run-time.
class Solution {
public: vector<vector<int>> threeSum(vector<int>& nums) {
int len = nums.size();
if(len<3) return {};
sort(nums.begin(), nums.end());
vector<vector<int>> retVector;
int target, begin, end;
int i=0;
while(i < len - 2)
{
int dup; // to find duplicates entries
target = -nums[i];
begin = i + 1; end = len - 1;
while (begin < end)
{
if (nums[begin] + nums[end] < target) begin++;
else if (nums[begin] + nums[end] > target) end--;
else
{
retVector.push_back({nums[i], nums[begin], nums[end]});
// its time to remove duplicates
dup=nums[begin];
do begin++; while(nums[begin] == dup); // removing from front
dup=nums[end];
do end--; while(nums[end] == dup); // removing from back
}
}
dup=nums[i];
do i++; while(nums[i] == dup) ; // removing all ertries same as nums[i]
}
return retVector;
}
};

C++ Vector Subscript out of Range Error 1221

I am trying to make a program that recieves numbers from the user, and then rearranges the from least to greatest. I am using vectors (which I just learned about), and it gives me a subscript out of range error. I am not able to find what part of the code gives me this error, so hopefully someone more knowledgeable on vector and c++ can find it:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void order(int a, int b);
void orderRev(int a, int b);
int main() {
vector<int> num;
bool going = true;
do {
cout << "\nEnter a number or type 'x' to order:" << endl;
string reply;
getline(cin, reply);
if (reply != "x") {
int a = atoi(reply.c_str());
num.push_back(a);
cout << "\nYou currently have " << num.size() << " numbers added." << endl;
}
else {
going = false;
}
} while (going);
for (int i = 0; i < num.size(); i++) {
order(num[i], num[i + 1]);
}
for (int i = num.size() - 1; i >= 0; i--) {
orderRev(num[i + 1], num[i]);
}
cout << "\nThe number you entered in order from least to greatest are: " << endl;
for (int i = 0; i < num.size(); i++) {
cout << num[i] << " ";
}
void order(int a, int b) {
if (a > b) {
int c = b;
b = a;
a = c;
}
}
void orderRev(int a, int b) {
if (a < b) {
int c = b;
b = a;
a = c;
}
}
Fix these lines to this:
// added the -1 as this will now go up to the 2nd to last element
// for `n`, and the last element for `n+1`
for (int i = 0; i < num.size() - 1; i++) {
order(num[i], num[i + 1]);
}
// changed the starting number to size -2 (for the same reasoning)
for (int i = num.size() - 2; i >= 0; i--) {
orderRev(num[i + 1], num[i]);
}
Why does this need to be this way? Think about how indices in C++ work. They are zero-indexed! That means that if you want both the element and the one in front of it, you must go up to the size of the vector minus 1. Hence, for a vector of 10 items (size 10), at i == 9 your code will work like this:
for (int i = 0; i < num.size(); i++) {
// i = 9
order(num[9], num[9+1]);// index 10 does not exist! Hence, you really need to go up to num.size() - 1!
}
Vectors index start with 0. index will be 0 to n-1 , if you use num[i + 1] it will exceed the vector size, if you don't check in loop condition.
Your code has more than one flaw. The output will be same as the input , hint: know the difference between pass by reference and pass by value and after that check some sorting algorithms.

Bubble sort issue

Currently studying software engineering at college (first year) and made a program where the user enters how many entries there will be and then they input the times for each entry and it is sorted in descending order.
The problem I am having is when I enter a large number for the first input it doesn't sort correctly but the rest do. It would be great if someone could help me out with this and sorry for the noob question:P
The entire code:
#include "stdafx.h"
#include <iostream>
using namespace std;
int TotalSize = 0;
void getSpeed(int *CalculationTime, int NoOfCalculations)
{
for (int i = 0; i < NoOfCalculations; i++)
{
cout << "Please enter the speed of calculation " << i + 1 << "(Ms): "; cin >> CalculationTime[i];
}
}
void sort_speeds(int *CalculationTime, int NoOfCalculations)
{
// Sorting speeds in decending order
bool swapped = true;
int i, j = 0;
int temp;
while (swapped)
{
swapped = false;
j++;
for (i = 1; i < NoOfCalculations - j; i++)
{
if (CalculationTime[i] > CalculationTime[i + 1])
{
temp = CalculationTime[i];
CalculationTime[i] = CalculationTime[i + 1];
CalculationTime[i + 1] = temp;
swapped = true;
}
}
}
// Output times decending order
for (int i = 0; i < NoOfCalculations; i++)
{
cout << CalculationTime[i] << "\n";
}
}
int main()
{
// Declaring & Initializing variables
int NoOfCalculations = 0;
int *CalculationTime = new int[NoOfCalculations];
// Getting user input
cout << "How many calculations are there? "; cin >> NoOfCalculations;
getSpeed(CalculationTime, NoOfCalculations);
// Sorting and displaying times
sort_speeds(CalculationTime, NoOfCalculations);
system("pause");
return 0;
}
You've never compare first element of your array with anything - for (i = 1; i < NoOfCalculations - j; i++) should be for (i = 0; i < NoOfCalculations - j; i++)
The issue is for (i = 1; i < NoOfCalculations - j; i++) You are starting at position 1, start at position 0 and it fixes the problem. for (i = 0; i < NoOfCalculations - j; i++)
// Declaring & Initializing variables
int NoOfCalculations = 0;
int *CalculationTime = new int[NoOfCalculations];
// Getting user input
cout << "How many calculations are there? "; cin >> NoOfCalculations;
Bzzzt. You allocate a zero-element array, and then don't reallocate it. I bet if you entered a large enough number for your number of calculations, your program would crash.
Really, you want to be using std::vector, an extremely useful datastructure, the use of which is a bit outside of the scope of this answer. Basically, you can do stuff like this:
std::vector<int> getSpeeds(int NoOfCalculations)
{
std::vector<int> speeds;
for (int i = 0; i < NoOfCalculations; i++)
{
int speed;
std::cout << "Please enter the speed of calculation " << i + 1 << "(Ms): ";
std::cin >> speed;
speeds.push_back(speed);
}
return speeds;
}
You can use the returned vector almost exactly as if it were an array:
std::vector<int> speeds = getSpeeds(10);;
if (CalculationTime[3] > CalculationTime[4])
// do something
Often, in a C++ application, the explicit use of pointers is a sign that you're not using the standard library, and as a result making life much, much harder for yourself.
Oh, and also:
for (i = 1; i < NoOfCalculations - j; i++)
You never look at NoOfCalculations[0] or NoOfCalculations[i - 1], so you never touch the first element.
while (swapped)
{
swapped = false;
j++;
for (i = 0; i < NoOfCalculations - j; i++) //try and start i from 0. I think you are missing the first element to check
{
if (CalculationTime[i] > CalculationTime[i + 1])
{
temp = CalculationTime[i];
CalculationTime[i] = CalculationTime[i + 1];
CalculationTime[i + 1] = temp;
swapped = true;
}
}
}