Bubble sort prevents my program from executing - c++

I am trying to make a bubble sort that will shift the position of several parallel arrays based on the string "desc", in ascending order. When I run the program, I just get a blank screen and the program never finishes.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
const int maxp = 50;
void swap(string& a, string& b)
{
string temp;
temp = a;
a = b;
b = temp;
}
//These swapem functions are the functions used to move the array
//values when the sort function is called
void swap(int& a, int& b)
{
int temp;
temp = a;
a = b;
b = temp;
}
void swap(char& a, char& b)
{
char temp;
temp = a;
a = b;
b = temp;
}
void swap(double& a, double& b)
{
double temp;
temp = a;
a = b;
b = temp;
}
void sort(int id[], string desc[], int numsold[], double price[],
double dolars[], int nump)
{
int i, j;
for (j = 0; j < nump - 1; j++)
for (i = 0; i = nump - 1; i++) //I'm sorting a group of parallel arrays by the
if (desc[i] > desc[i+1])//string "desc", and the others are being moved based off of that
{
swapem(desc[i], desc[i + 1]);
swapem(id[i], id[i + 1]);
swapem(numsold[i], numsold[i + 1]);
swapem(price[i], price[i + 1]);
swapem(dolars[i], dolars[i + 1]);
}
}
int main()
{
int id[maxp], numsold[maxp], nump;
double price[maxp], dolars[maxp];
string desc[maxp];
ifstream inf;
ofstream outf;
inf.open("storesales.dat");
outf.open("storesales.ot");
outf.setf(ios::fixed);
outf.precision(2);
initem(desc, id, numsold, nump, price, dolars);
readem(id,numsold,nump,price,desc);
printem(id, desc, numsold,nump, price, outf);
getsales(numsold, price, dolars,nump);
sortem(id, desc, numsold, price, dolars, nump);
printem(desc, id, numsold, nump, price, dolars, outf);
system("pause");
}
I know that these functions are the problem because I retested them and commented the calls out, the program finished. The problem is, I don't know what is wrong.

Nasted loop in sortem():
for (i = 0; i = nump - 1; i++)
should be condition instead of assignment i.e:
for (i = 0; i < nump - 1; i++)
Second parameter of for loop is expected condition. Assignment i = nump always return true thereby infinite loop. As a result, your blank screen.

the error is in the 2nd loop
for best performance you can have the inner loop as follows:
for (i = j; i < nump - 1; i++)

As this is already answered just few silly suggestions:
Why are you want j to loop nump-1 times?
You should stop when no swap in the nested loop occurs... which mean stop when sorting is done. Otherwise your sort will always take the worst case runtime.
for (j=1;j;) // loop while j is set
for (j=0,i=0;i<nump-1;i++) // reset j
if (desc[i] > desc[i+1]) // if swap needed
{
swapem(desc[i], desc[i + 1]); // swap elements
swapem(id[i], id[i + 1]);
swapem(numsold[i], numsold[i + 1]);
swapem(price[i], price[i + 1]);
swapem(dolars[i], dolars[i + 1]);
j=1; // and set j so this loops until array is ordered
}
Also you are using parallel arrays which have its merits but I think in your case use of struct or class would be far better simplifying the code (especially the swap) a bit having single array with all the info inside.

Related

Mergesort incorrect output c++

Input : {10,9,8,7,6,5,4,3,2,1}
Output : {8,7,6,9,10,5,4,3,2,1}
I'm not sure what the issue is. I think it has something to do with the recursion in mergesort. I'm new to recursion so my understanding is not too good. Any hints?
#include <iostream>
void mergeSort(int a[], int w[], int n);
void merge(int a[], int w[], int n);
using namespace std;
void mergeSort(int a[], int t[], int n) {
if (n > 1) {
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
for (int i = n/2; i < n; i++) {
t[i] = a[i];
}
mergeSort(a, t, n/2);
merge(a, t, n/2);
}
}
void merge(int a[], int t[], int n) {
int leftIndex = 0, leftEnd = n/2;
int rightIndex = n/2, rightEnd = n;
int targetIndex = 0;
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < t[rightIndex])
a[targetIndex++] = t[leftIndex++];
else
a[targetIndex++] = t[rightIndex++];
}
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
while (rightIndex < rightEnd) {
a[targetIndex++] = t[rightIndex++];
}
}
int main() {
const int SIZE = 10;
int a[] = {10,9,8,7,6,5,4,3,2,1};
int w[SIZE];
mergeSort(a,w,SIZE);
for (int i = 0; i < SIZE; i++) {
cout << a[i] << " ";
}
cout << endl;
}
The general problem is pointer confusion. One of the C language quirks that is not immediately obvious is that in
void mergeSort(int a[], int t[], int n);
both a and t are not arrays, but pointers. There is a special rule for this in the language standard. What this means is that in all instantiations of mergeSort on the call stack, t and a refer to the same areas of memory, and this means that every time you do something like
for (int i = 0; i < n/2; i++) {
t[i] = a[i];
}
you're changing the same region of memory. After you've done so and returned to the previous call frame, this region no longer contains the data you expect it to contain.
The way to solve this is to define a temporary local buffer where you need it, which is in merge. For example:
const int SIZE = 10;
// mergeSort is much simpler now:
void mergeSort(int a[], int n) {
if (n > 1) {
// sort the left side, then the right side
mergeSort(a , n / 2);
mergeSort(a + n / 2, n - n / 2);
// then merge them.
merge(a, n);
}
}
// Buffer work done in merge:
void merge(int a[], int n) {
// temporary buffer t, big enough to hold the left side
int t[SIZE];
int leftIndex = 0 , leftEnd = n / 2;
int rightIndex = n / 2, rightEnd = n ;
int targetIndex = 0;
// copy the left side of the target array into the temporary
// buffer so we can overwrite that left side without worrying
// about overwriting data we haven't yet merged
for(int i = leftIndex; i < leftEnd; ++i) {
t[i] = a[i];
}
// then merge the right side and the temporary buffer to
// the left side. By the time we start overwriting stuff on
// the right side, the values we're overwriting will have been
// merged somewhere into the left side, so this is okay.
while (leftIndex < leftEnd && rightIndex < rightEnd) {
if (t[leftIndex] < a[rightIndex]) {
a[targetIndex++] = t[leftIndex++];
} else {
a[targetIndex++] = a[rightIndex++];
}
}
// If there's stuff in the temporary buffer left over,
// copy it to the end of the target array. If stuff on the
// right is left over, it's already in the right place.
while (leftIndex < leftEnd) {
a[targetIndex++] = t[leftIndex++];
}
}
Before explaining the errors, let me first emphasize that a function argument like int a[] is nothing more than a pointer passed to the function. It points to a region of memory.
Now, mergesort requires some temporary memory and works by
copying the data to the temporary memory;
sorting each half of the data in temporary memory;
merging the two halves, whereby writing into the original array.
In step 2, the original array is not needed and can serve as temporary memory for the recursion.
In view of these facts, your code contains two errors:
You don't use the arrays t[] and a[] appropriately. The idea is that a[] is both input and output and t[] a temporary array. Internally, data are first copied to the temporary array, each half of which is sorted, before merging them fills the original array a[].
You don't sort the second half of the temporary array, but the first half twice.
A correct implementation is, for example,
void mergeSort(int*a, int*t, int n) {
if (n > 1) {
for (int i = 0; i < n; i++)
t[i] = a[i]; // copy to temporary
mergeSort(t , a , n/2); // sort 1st half of temporary
mergeSort(t+n/2, a+n/2, n-n/2); // sort 2nd half of temporary
merge(a, t, n);
}
}
Note that since t[] and a[] are pointers, the operation t+n/2 simply obtains the pointer to the second half of the array. The result of your code with this alteration is 1 2 3 4 5 6 7 8 9 10.

Implementing quicksort on strings

I'm trying to implement the quicksort on a string of characters. The output should give me an alphabetical order version of the input, however right now it's just giving me the original input. This was an attempt trying to translate the pseudo code from Intro to Algorithm 3rd edition on Quicksort.
Any help would be greatly appreciated, thanks!
Here's the pseudo code of quicksort from the book
#include <string>
#include <iostream>
#include <stdlib.h>
using namespace std;
int partition_str(string A, int start, int finish){
char x = A[finish], temp;
int i = start - 1;
for (int j = start; j <= finish -1; j++){
if (A[j] <= x){
i ++;
temp = A[i]; A[i] = A[j]; A[j] = temp;
}
temp = A[i+1]; A[i+1] = A[finish]; A[finish] = temp;
return i+1;
}
}
string quicksort_char(string A, int start, int finish)
{
if (start < finish)
{
start = partition_str(A, start, finish);
quicksort_char(A, start, finish -1);
quicksort_char(A, start+1, finish);
}
return A;
}
int main(){
string test = "gsgkdsdkjs";
string result = quicksort_char(test, 0, 10);
cout << result << endl;
return 0;
}
In the pseudocode you linked, it mentions that partition() alters subarrays in place. This insinuates that you need to pass by reference, rather than by value. Notice the ampersand (&) I add in the function signature. Your code was passing by value, so it was making a copy of the input string, rather than altering it in place. In your quicksort() function, you wrote the code expecting that A will be altered by the function.
I cleaned up your code a bit here with the intent of making it clearer and look more like the pseudocode...
#include <iostream>
#include <string>
using namespace std;
void exchange(char& a, char& b)
{
char value_of_a = a;
char value_of_b = b;
a = value_of_b;
b = value_of_a;
};
int partition(string& A, int p, int r)
{
char x = A[r];
int i = p-1;
for (int j=p; j<=(r-1); ++j)
{
if (A[j] <= x)
{
i++;
exchange(A[i], A[j]);
}
}
exchange(A[i+1], A[r]);
return i+1;
};
void quicksort(string& A, int p, int r)
{
if (p < r)
{
int q = partition(A, p, r);
quicksort(A, p, q-1);
quicksort(A, q+1, r);
}
};
int main()
{
string input = "gsgkdsdkjs";
cout << "input string: " << input << endl;
quicksort(input, 0, input.size());
cout << "sorted string: " << input << endl;
return 0;
}
In your partition_str() function you pass in string A by value, which makes a copy of A rather than using the same A you passed in. It then performs some operations and returns an integer. The copy of A is then thrown away and your original A variable was never modified. This means that if you want your variable A to be changed, you must pass by reference.
Also, don't be confused by the function argument naming. Your partition_str() function signature is:
int partition_str(string A, int start, int finish)
The fact the 'string A' is defined as an argument does not mean that it is related to any other variable in your code called 'A'. It is merely a way of referring to particular argument that was passed in.

this is a code for left rotation of an array....how to optimize it further as it's giving TLE error

#include <iostream>
using namespace std;
int main() {
int n,d,i=0,temp;
cin>>n>>d;
int a[1000000];
for(i=0;i<n;i++){
cin>>a[i];
}
while(d--){
temp=a[0];
for(i=1;i<n;i++){
a[i-1]=a[i];}
a[n-1]=temp;
}
for(i=0;i<n;i++){
cout<<a[i]<<" ";
}
return 0;
}
how to optimize it further as it's giving TLE error. the input file is very large obviously.
Some suggestions:
Rotate by the full amount d in a single loop (note that the result is a different array b):
for (i = 0; i < n; i++) {
b[(i+n-d) % n]=a[i];
}
Don't touch the array at all but transform the index when accessing it, for example:
cout << a[(i+n-d) % n] << " ";
The second version requires extra calculation to be done whenever accessing an array element but it should be faster if you don't need to access all array elements after each rotate operation.
There is also a way to do the rotation in-place by using a helper function that reverses a range of the array. It's a bit odd but might be the best solution. For convenience I have used a std::vector instead of an array here:
void ReverseVector( std::vector<int>& a, int from, int to ) {
for (auto i = 0; i < (to - from) / 2; i++) {
auto tmp = a[from + i];
a[from + i] = a[to - i];
a[to-i] = tmp;
}
}
void RotateVector( std::vector<int>& a, int distance ) {
distance = (distance + a.size()) % a.size();
ReverseVector( a, 0, a.size() - 1 );
ReverseVector( a, 0, distance - 1 );
ReverseVector( a, distance, a.size() - 1 );
}

How to optimise the O(m.n) solution for longest common subsequence?

Given two strings string X of length x1 and string Y of length y1, find the longest sequence of characters that appear left to right (but not necessarily in contiguous block) in both strings.
e.g if X = ABCBDAB and Y = BDCABA, the LCS(X,Y) = {"BCBA","BDAB","BCAB"} and LCSlength is 4.
I used the standard solution for this problem:
if(X[i]=Y[j]) :1+LCS(i+1,j+1)
if(X[i]!=Y[j]) :LCS(i,j+1) or LCS(i+1,j), whichever is greater
and then I used memorization, making it a standard DP problem.
#include<iostream>
#include<string>
using namespace std;
int LCS[1024][1024];
int LCSlen(string &x, int x1, string &y, int y1){
for(int i = 0; i <= x1; i++)
LCS[i][y1] = 0;
for(int j = 0; j <= y1; j++)
LCS[x1][j] = 0;
for(int i = x1 - 1; i >= 0; i--){
for(int j = y1 - 1; j >= 0; j--){
LCS[i][j] = LCS[i+1][j+1];
if(x[i] == y[j])
LCS[i][j]++;
if(LCS[i][j+1] > LCS[i][j])
LCS[i][j] = LCS[i][j+1];
if(LCS[i+1][j] > LCS[i][j])
LCS[i][j] = LCS[i+1][j];
}
}
return LCS[0][0];
}
int main()
{
string x;
string y;
cin >> x >> y;
int x1 = x.length() , y1 = y.length();
int ans = LCSlen( x, x1, y, y1);
cout << ans << endl;
return 0;
}
Running here, this solution I used in SPOJ and I got a time limit exceeded and/or runtime error.
Only 14 user solutions are yet accepted. Is there a smarter trick to decrease the time complexity of this question?
LCS is a classical, well studied computer science problem, and for the case with two sequences it is known that its lower bound is O(n·m).
Furthermore, your algorithm implementation has no obvious efficiency bugs, so it should run close to as fast as possible (although it may be beneficial to use a dynamically sized 2D matrix rather than an oversized one, which takes up 4 MiB of memory, and will require frequent cache invalidation (which is a costly operation, since it causes a transfer from main memory to the processor cache, which is several orders of magnitude slower than cached memory access).
In terms of algorithm, in order to lower the theoretical bound you need to exploit specifics of your input structure: for instance, if you are searching one of the strings repeatedly, it may pay to build a search index which takes some processing time, but will make the actual search much faster. Two classical variants of that are the suffix array and the suffix tree.
If it is known that at least one of your strings is very short (< 64 characters) you can use Myers’ bit vector algorithm, which performs much faster. Unfortunately the algorithm is far from trivial to implement. There exists an implementation in the SeqAn library, but using the library itself has a steep learning curve.
(As a matter of interest, this algorithm finds frequent application in bioinformatics, and has been used during the sequence assembly in the Human Genome Project.)
Although I still didn't get an AC because of time limit exceeded ,I was however able to implement the linear space algorithm.In case anyone wants to see, here is the c++ implementation of the Hirschbirg algorithm.
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
int* compute_help_table(const string & A,const string & B);
string lcs(const string & A, const string & B);
string simple_solution(const string & A, const string & B);
int main(void) {
string A,B;
cin>>A>>B;
cout << lcs(A, B).size() << endl;
return 0;
}
string lcs(const string &A, const string &B) {
int m = A.size();
int n = B.size();
if (m == 0 || n == 0) {
return "";
}
else if(m == 1) {
return simple_solution(A, B);
}
else if(n == 1) {
return simple_solution(B, A);
}
else {
int i = m / 2;
string Asubstr = A.substr(i, m - i);
//reverse(Asubstr.begin(), Asubstr.end());
string Brev = B;
reverse(Brev.begin(), Brev.end());
int* L1 = compute_help_table(A.substr(0, i), B);
int* L2 = compute_help_table(Asubstr, Brev);
int k;
int M = -1;
for(int j = 0; j <= n; j++) {
if(M < L1[j] + L2[n-j]) {
M = L1[j] + L2[n-j];
k = j;
}
}
delete [] L1;
delete [] L2;
return lcs(A.substr(0, i), B.substr(0, k)) + lcs(A.substr(i, m - i), B.substr(k, n - k));
}
}
int* compute_help_table(const string &A, const string &B) {
int m = A.size();
int n = B.size();
int* first = new int[n+1];
int* second = new int[n+1];
for(int i = 0; i <= n; i++) {
second[i] = 0;
}
for(int i = 0; i < m; i++) {
for(int k = 0; k <= n; k++) {
first[k] = second[k];
}
for(int j = 0; j < n; j++) {
if(j == 0) {
if (A[i] == B[j])
second[1] = 1;
}
else {
if(A[i] == B[j]) {
second[j+1] = first[j] + 1;
}
else {
second[j+1] = max(second[j], first[j+1]);
}
}
}
}
delete [] first;
return second;
}
string simple_solution(const string & A, const string & B) {
int i = 0;
for(; i < B.size(); i++) {
if(B.at(i) == A.at(0))
return A;
}
return "";
}
Running here.
If the two strings share a common prefix (e.g. "ABCD" and "ABXY" share "AB") then that will be part of the LCS. Same for common suffixes. So for some pairs of strings you can gain some speed by skipping over the longest common prefix and longest common suffix before starting the DP algorithm; this doesn't change the worst-case bounds, but it changes the best case complexity to linear time and constant space.

C++ multidimensional array of struct

I'm writing a program that counts all binary trees with n nodes and height k. Every node has 0 or 2 children. The program works but I wanted to add some memoization because the answer is always the same for some particular n and k.
I could create an multidimensional array of pairs but I already have my useful struct now. How could I declare and use this mem variable. I didn't find a good answer on this. I understand pointers but I would prefer a method without memory management.
This is an exercise from the USACO training program btw.
#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
using namespace std;
struct state {
int down, half;
state(int d, int h) : down(d), half(h) {}
int valid() {
return down != -1 && half != -1;
}
};
state mem[200][100];
state cnt(int n, int k)
{
if (mem[n][k].valid())
return mem[n][k];
if (n == 1)
return state(k == 1, k != 1);
if (n > pow(2, k) - 1)
return state(-1, -1);
state total(0, 0);
for (int i = 1; i < n - 1; ++i) {
state left = cnt(i, k - 1);
state right = cnt(n - i - 1, k - 1);
if (left.valid() && right.valid()) {
total.down += left.down * right.down +
left.down * right.half +
left.half * right.down;
total.half += left.half * right.half;
}
}
return mem[n][k] = state(total.down % 9901, total.half % 9901);
}
int main()
{
ofstream fout ("nocows.out");
ifstream fin ("nocows.in");
int n, k;
fin >> n >> k;
for (int i = 0; i <= n; ++i)
for (int j = 0; j <= k; ++j)
mem[i][j] = state(-1, -1);
cout << cnt(n, k).down << endl;
return 0;
}
You can use a vector of vectors:
std::vector<std::vector<state> > mem;
You can dynamically add to it and needn't worry about size (although if you roughly know the size, you can pre-allocate it to avoid resizing), and also memory clean-up is automatic - when the vector goes out of scope, its components will also be deleted.
Your code doesn't work because you don't have a default constructor for state.
The thing is, when you write state mem[200][100]; the compiler will try to create 100*200 state objects, but it can't. To make this work, you'd need a default constructor in state:
struct state {
state() : down(0), half(0) {} //default constructor
int down, half;
state(int d, int h) : down(d), half(h) {}
int valid() {
return down != -1 && half != -1;
}
};