#include <iostream>
#include <string>
using namespace std;
//Iterates over the string array appNames displaying each application
//name in a separate line. There are appCount elements in the array
void displayAllApplicationNames(string appNames[], int appCount);
//Swaps strings in string array appNames between appIndex1 and appIndex2
void swapAppNames(int appIndex1, int appIndex2, string appNames[]);
//Splits string array appNames around a pivot index p (the pivot).
//Elements below index p are less than elements above index p.
//The function returns the pivot p
int pivot(int first, int last, string appNames[]);
//Implements the QuickSort algorithm to sort string array
//appNames between indeces first and last
void quickSort(int first, int last, string appNames[]);
void main()
{
string appNames[] =
{
"4) Pages", "2) Keynote", "3) Numbers",
"8) Word", "5) PowerPoint", "1) Excel",
"0) Documents", "6) Presentation", "7) Sheets"
};
displayAllApplicationNames(appNames, 9);
swapAppNames(3, 6, appNames);
displayAllApplicationNames(appNames, 9);
quickSort(0, 8, appNames);
displayAllApplicationNames(appNames, 9);
getchar();
}
void displayAllApplicationNames(string appNames[], int appCount)
{
for(appCount = 0; appCount <= 8; appCount++)
{
cout << "[" << appCount << "]\t"<< appNames[appCount] << endl;
}
if( appCount < 0 || appCount > 8)
{
cout << "_________" <<endl;
}
}
void swapAppNames(int appIndex1, int appIndex2, string appNames[])
{
string temp = appNames[appIndex1];
appNames[appIndex1] = appNames[appIndex2];
appNames[appIndex2] = temp;
}
int pivot(int first, int last, string appNames[])
{
int pivotIndex, mid = (first + last) / 2;
swapAppNames(first, mid, appNames);
pivotIndex = first;
string pivotValue = appNames[first];
for (int i = first + 1; i <= last; i++)
{
if (appNames[i] < pivotValue)
{
pivotIndex++;
swapAppNames(pivotIndex, i, appNames);
}
swapAppNames(first, last, appNames);
return pivotIndex;
}
}
void quickSort(int first, int last, string appNames[])
{
if (first < last)
{
int p = pivot( first, last, appNames);
quickSort( first, p - 1, appNames);
quickSort( p + 1, last, appNames);
}
}
My goal is to sort the names in the string array "appNames". I added numbers to the names to show what order they SHOULD be in, but when I run the program, it doesn't seem to be sorting correctly at all. can anyone tell me where I'm going wrong?
I've been looking at this for a few days to no avail.
Edit: Here's the solution. Big thanks to everyone who replied. Had to swap the position of a few variables and read up on the quicksort algorithm.
int pivot(int first, int last, string appNames[])
{
int pivotIndex, mid = (first + last) / 2;
swapAppNames(first, mid, appNames);
pivotIndex = first;
string pivotValue = appNames[first];
for (int i = first + 1; i <= last; i++)
{
if (appNames[i] < pivotValue)
{
pivotIndex++;
swapAppNames(pivotIndex, i, appNames);
}
}
swapAppNames(pivotIndex, first, appNames);
return pivotIndex;
}
Your code, as you posted it, is still not correct. Here is a working version. I made a couple of changes.
I removed the mid heuristic from your pivot function. It is noise unless your assignment explicitly asked you to consider worst case scenarios. And if it did, then there are better heuristics to use. I also changed the way swapping works to a less efficient, but hopefully more intuitive version.
The other change was to the meaning of last as it was used in your quickSort and pivot interfaces. It is better if last means "one past the end". If last is actually the last item then you have no way to represent an empty list. In your notation (0,0) has length 1, (0,1) has length 2, etc. and the length is calculated as (last - first) + 1. If last is "one past the end", then the empty list is (0,0), (0,1) has length 1, etc. and the length is simply (last - first). If you carry on with C++ you will see that this is the way the STL works, so it is useful to learn it now.
#include <iostream>
#include <string>
using namespace std;
//Iterates over the string array appNames displaying each application
//name in a separate line. There are appCount elements in the array
void displayAllApplicationNames(string appNames[], int appCount);
//Swaps strings in string array appNames between appIndex1 and appIndex2
void swapAppNames(int appIndex1, int appIndex2, string appNames[]);
//Splits string array appNames around a pivot index p (the pivot).
//Elements below index p are less than elements above index p.
//The function returns the pivot p
int pivot(int first, int last, string appNames[]);
//Implements the QuickSort algorithm to sort string array
//appNames between indices first and last
void quickSort(int first, int last, string appNames[]);
int main() {
string appNames[] = {
"4) Pages", "2) Keynote", "3) Numbers",
"8) Word", "5) PowerPoint", "1) Excel",
"0) Documents", "6) Presentation", "7) Sheets" };
displayAllApplicationNames(appNames, 9);
swapAppNames(3, 6, appNames);
displayAllApplicationNames(appNames, 9);
quickSort(0, 9, appNames);
displayAllApplicationNames(appNames, 9);
return 0; }
void displayAllApplicationNames(string appNames[], int appCount) {
for (int i = 0; i < appCount; ++i) {
cout << "[" << i << "]\t" << appNames[i] << endl; }
cout << "_________" << endl; }
void swapAppNames(int appIndex1, int appIndex2, string appNames[]) {
string temp = appNames[appIndex1];
appNames[appIndex1] = appNames[appIndex2];
appNames[appIndex2] = temp; }
int pivot(int p, int n, string a[]) {
for (int i = p + 1; i < n; ++i) {
if (a[i] < a[p]) {
swapAppNames(i, p + 1, a);
swapAppNames(p, p + 1, a);
++p; } }
return p; }
void quickSort(int first, int last, string a[]) {
if (first < last) {
int p = pivot(first, last, a);
quickSort(first, p, a);
quickSort(p + 1, last, a); } }
Related
I am new to programming. I have been struggling with this programme for a long time.
Question:
what logic error am I having with my code?
Problem:
need to find the maximum subsequence of a string. The length of the required subsequence, and the content of the string are from input.
for example, maximum subsequence with length 3 of string "abcde" is "cde".
the subsequence retrieved should have the same order as the original string
EDIT: A subsequence is a subset of the input string "I" arranged in the original order.
The maximum subsequence in this question is the largest one (in alphabetical order) of those subsequences with length K.
For instance, why in the case AbCd687fs 4 the subsequence is not"bdfs" but "d8fs"? The reason is that "d8fs" is larger than "bdfs" in alphabetical order
for 1265432 2. You can get some subsequence with length 2, e.g., 12, 16, 15, 14, 13, 26, 25, 24, 23, 22, 65, 64, 63,62,54,... . And in alphabetical order, the subsequence "65" is the maximum.
For AbCd687fs 4. You can get some subsequence with length 4, e.g., AbCd, AbC6, bCd6, bC8s,d687, d87f, d8fs, d7fs,... . And in alphabetical order, the subsequence " d8fs" is the maximum.
My approach:
initialize string buffer with same length of I, filled with '*' : string buffer(I.length(),'*')
inner for loop to find the largest character in string I
replace the character into the string buffer with the same index position of the character in string I
remove the current largest character in string I. Then go through the for loop again to find the next largest character in string I.
while loop with number of iterations same as value of K to run the for loop K times
When the while loop ends, remove all the '*' from string buffer. The remaining content should be the maximum subsequence only.
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string I;
cout << "Please input a string:" << endl;
cin >> I;
int K;
cout << "Please input the length of subsequence:" << endl;
cin >> K;
string buffer(I.length(), '*');
int pos;
while (K>0)
{
char vMax = I[0];
for (int i = 0; i < I.length(); i++)
{
if (I[i] > vMax)
{
vMax = I[i];
}
}
pos = I.find(vMax);
//buffer.insert(pos, I, pos, 1);
buffer.replace(pos, 1, I, pos, 1);
I.erase(remove(I.begin(), I.end(), vMax), I.end());
K--;
}
buffer.erase(remove(buffer.begin(), buffer.end(), '*'), buffer.end());
cout << "The maximum subsequence is: ";
for (int i = 0; i < buffer.length(); i++)
{
cout << buffer[i];
}
}
Your current code has a big problem since you erase characters from I and therefore can't calculate the pos in the original string properly.
I suggest that you use std::max_element to get an iterator to the char with the largest value instead of doing the search manually.
Here's how to fix it using AbCd687fs 4 as an example:
Search for the char with the largest value in the range AbCd68 (7fs not included because we must be able to find 4 characters in total). d is found.
Search the range 687 (AbCd and fs are not included), 8 is found.
Search the range 7f (AbCd68 and s are not included). f is found.
Search the range s (AbCd687f are not included). s is found.
Implemented:
#include <algorithm> // std::max_element
#include <iterator> // std::prev
std::string get_substr(const std::string& I, size_t K) {
std::string buffer;
buffer.reserve(K);
for(auto maxit = I.begin(); K --> 0; ++maxit) {
maxit = std::max_element(maxit, std::prev(I.end(), K));
buffer += *maxit;
}
return buffer;
}
Demo
I made modifications to your code and this should most probably help you:
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int main()
{
string I;
cout << "Please input a string:" << endl;
cin >> I;
int K;
cout << "Please input the length of subsequence:" << endl;
cin >> K;
string buffer(I.length(), '*');
int pos;
while (K>0)
{
char vMax = I[0];
for (int i = 0; i < I.length(); i++)
{
if (I[i] > vMax)
{
vMax = I[i];
}
}
pos = I.find(vMax);
//buffer.insert(pos, I, pos, 1);
buffer.at(pos) = vMax;
I.at(pos) = ' '; //Space has the least ascii value in printable characters
//buffer.replace(pos, 1, I, pos, 1);
//I.erase(remove(I.begin(), I.end(), vMax), I.end());
K--;
}
buffer.erase(remove(buffer.begin(), buffer.end(), '*'), buffer.end());
cout << "The maximum subsequence is: ";
for (int i = 0; i < buffer.length(); i++)
{
cout << buffer[i];
}
}
Reading code which is in one single function is hard. So my advice for the future, split code into smaller pieces.
Instead reading your code I've wrote my solution:
using Histogram = std::array<size_t, 128>;
auto makeFullHistogram(const std::string& s)
{
Histogram r{};
for (auto ch : s) ++r[ch];
return r;
}
void clipLeadingValuesOfHistogram(Histogram& hist, size_t len)
{
for (auto it = hist.rbegin(); it != hist.rend(); ++it) {
if (len) {
if (len < *it) {
*it = len;
}
len -= *it;
} else {
*it = 0;
}
}
}
auto findLeadingValuesHistogram(const std::string& s, size_t len)
{
auto hist = makeFullHistogram(s);
clipLeadingValuesOfHistogram(hist, len);
return hist;
}
std::string bestSubstring(const std::string& s, size_t len)
{
std::string r;
r.reserve(len);
auto hist = findLeadingValuesHistogram(s, len);
for (auto ch : s) {
if (hist[ch]) {
--hist[ch];
r += ch;
if (r.size() == len) break;
}
}
return r;
}
Learning writing tests is also helpful:
https://godbolt.org/z/93aY4aafs
Need to move all values which is less than 1 in begin of array (WITHOUT SORT, and need solution without second array)
for example:
START ARRAY: {-2.12, -3, 7.36, 6.83, -1.82, 7.01}
FINISH ARRAY: {-2.12, -3, -1.82, 7.36, 6.83, 7.01}
There is my solution but it doesn't work very well, because at final we receive:
FINISH ARRAY: {-2.12, -3, -1.82, 6.83, 7.36, 7.01}
Values which less than 1, moves to begin of array, but 4 and 5 elements not in correct order
#include <iostream>
using namespace std;
int main() {
double arr[6] = {-2.12, -3, 7.36, 6.83, -1.82, 7.01};
cout << "Start array: " << endl;
for (int x = 0; x < 6; x++) {
cout << arr[x] << ", ";
}
int index=0;
double temp;
for (int i = 0; i < 6; i++) {
if (arr[i] < 1) {
temp=arr[i];
arr[i] = arr[index];
arr[index] = temp;
index++;
}
}
cout << endl << "FINISH ARRAY: " << endl;
for (int x = 0; x < 6; x++) {
cout << arr[x] << ", ";
}
return 0;
}
Use std::stable_partition:
std::stable_partition(std::begin(arr), std::end(arr),
[](double d) { return d < 1; });
If you want to implement it yourself, note, that in-place stable partition (using comparisons and swaps) cannot be done better than in O(N log N) time. Any algorithm with O(N) running time is incorrect.
One possible solution can be obtained with divide-and-conquer approach:
template<class It, class Pred>
It stable_partition(It first, It last, Pred pred) {
// returns the iterator to the first element of the second group:
// TTTTTFFFFFF
// ^ return value
if (first == last)
return last;
if (last - first == 1) {
if (pred(*first)) // T
return last; // ^ last
else // F
return first; // ^ first
}
// Split in two halves
const auto mid = first + (last - first) / 2;
// Partition the left half
const auto left = stable_partition(first, mid, pred);
// TTTTTFFFFF
// ^ left
// ^ mid
// Partition the right half
const auto right = stable_partition(mid, last, pred);
// TTTTTFFFFF
// ^ right
// ^ mid
// Rotate the middle part: TTTTTFFFFFTTTTTFFFFF
// ~~~~~~~~~~
// ^ left ^ right
// ^ mid
const auto it = std::rotate(left, mid, right);
// TTTTTTTTTTFFFFFFFFFF
// ^ it
return it;
}
It resembles quicksort, but here we do not actually sort the range. std::rotate itself can be easily implemented via three reverses.
My assignment is to create a linear and binary search algorithm, and display the number of counts it takes to find the inputted value.
i have tried to use probes to count them but it gave me an error of lnk2019. What is another way of displaying the number of comparisons on the screen?
Here is the assignment:
Write a program that has an array of at least 25 integers. It should call a function that uses the linear search algorithm to locate one of the values. The function should keep a count of the number of comparisons it makes until it finds the value. The program then should call a function that uses the binary search algorithm to locate the same value. It should also keep count of the number of comparisons it makes. Display these values on the screen.
`
#include <iostream>
using namespace std;
int linearSearch(int a[], int size, int target);
int binarySearch(const int array[], int size, int value);
int main(void)
{
//linear search
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25 };
int result;
int userNum;
cout << "enter any number between 1 and 25\n";
cin >> userNum;
result = linearSearch(arr, 25, userNum);
if (result == -1)
cout << "Not found in linear search\n";
else
cout << "Linear search : Found at element " << result << endl;
//binary search
result = binarySearch(arr, 25, userNum);
if (result == -1)
cout << "Not found in binary search\n";
else
{
cout << "Binary search : Found at element " << result << endl;
}
return 0;
}
int linearSearch(int a[], int size, int target, int &numProbes)
{
int index = 0;
numProbes = 0;
for (int index = 0; index < size; index++)
numProbes++;
if (target == a[index])
return index;
return -1;
}
int binarySearch(const int array[], int size, int value, int &numProbes)
{
int first = 0,
last = size - 1,
middle,
position = -1;
bool found = false;
numProbes = 0;
while (!found && first <= last)
{
numProbes++;
middle = (first + last) / 2;
if (array[middle] == value)
{
found = true;
position = middle;
}
else if (array[middle] > value)
last = middle - 1;
else first = middle + 1;
}
return position;
} `
The problem you have is that the definition of your binarySearch function doesn't match it's declaration (you have one more parameter in definition).
The easiest solution is to move the main() function to the end of the file and get rid of the declaration of your functions, thus getting clear error messages on the compilation phase.
So I have written this quick sort function, and it works for SOME input.
For example it works for the following inputs : "5 4 3 2 1", "3 4 5 6 7", etc.
However when I input something like : "0 3 5 4 -5 100 7777 2014" it will always mix up the multi digit numbers.
I was hoping someone could help point me to where my code is failing at this test case.
Sort.cpp
std::vector<int> QuickSort::sortFunc(std::vector<int> vec, int left, int right) {
int i = left, j = right;
int tmp;
int pivot = vec.at( (left + right) / 2 );
/* partition */
while (i <= j) {
while (vec.at(i) < pivot)
i++;
while (vec.at(j) > pivot)
j--;
if (i <= j) {
tmp = vec.at(i);
vec.at(i) = vec.at(j);
vec.at(j) = tmp;
i++;
j--;
}
}
/* recursion */
if (left < j)
return sortFunc( vec, left, j );
if (i < right)
return sortFunc( vec, i, right );
else
{
return vec;
}
}
main.cpp
int main()
{
// The user inputs a string of numbers (e.g. "6 4 -2 88 ..etc") and those integers are then put into a vector named 'vec'.
std::vector<int> vec;
// Converts string from input into integer values, and then pushes said values into vector.
std::string line;
if ( getline(std::cin, line) )
{
std::istringstream str(line);
int value;
str >> value;
vec.push_back( value );
while ( str >> value )
{
vec.push_back( value );
}
}
// Creating QuickSort object.
QuickSort qSort;
QuickSort *ptrQSort = &qSort;
// Creating new vector that has been 'Quick Sorted'.
int vecSize = vec.size();
std::vector<int> qSortedVec;
qSortedVec = ptrQSort->sortFunc( vec, 0, vecSize-1 );
// Middle, start, and end positions on the vector.
int mid = ( 0 + (vec.size()-1) ) / 2;
int start = 0, end = vec.size() - 1;
// Creating RecursiveBinarySearch object.
RecursiveBinarySearch bSearch;
RecursiveBinarySearch *ptrBSearch = &bSearch;
//bool bS = ptrBSearch->binarySearch( qSortedVec, mid, start, end );
bool bS = ptrBSearch->binarySearch( bSortedVec, mid, start, end );
/*--------------------------------------OUTPUT-----------------------------------------------------------------------*/
// Print out inputted integers and the binary search result.
// Depending on the binary search, print either 'true' or 'false'.
if ( bS == 1 )
{
std::cout << "true ";
}
if ( bS == 0 )
{
std::cout << "false ";
}
// Prints the result of the 'quick sorted' array.
int sortedSize = qSortedVec.size();
for ( int i = 0; i < sortedSize; i++ )
{
std::cout << qSortedVec[i] << " ";
}
std::cout << "\n";
return 0;
}
Thanks for any and all help you can give me guys.
I'm not sure if this solves it completely, but after sorting the left part, you still need to sort the right part, but you already return instead.
Also, passing the vector by value and returning it is overhead and not needed, because in the end there should only be one version of the vector, so passing by reference is preferred. Passing by value and returning is sometimes needed when doing recursion, especially when backtracking (looking for different paths), but not in this case where left and right provide the needed state.
FYI: I am new to programming.
I have an arraysize of 10 and the sentinel value is 0.
My original array is [1 2 3] ( user input) but my reverse is [0 0 0 0 0 0 0 3 2 1].
I need help to make my reverse array [3 2 1].
Here is my code:
int temp;
for (int i = 0; i < arraysize/2; i++)
{
temp = array[arraysize-1-i];
array[arraysize - i - 1] = array[i];
array[i] = temp;
}
cout << "The reverse array: ";
for (int i = 0; i < arraysize; i++)
cout << array[i]<< ' ';
cout << endl;
Just use the standard library algorithms
auto end = std::find(std::begin(array),std::end(array),0);
std::reverse(std::begin(array),end);
//And if you only want to print the non-zero values:
size_t effectiveArraySize = end - std::begin(array);
If the fixed size array is not part of your requirement, you should put your user data in a vector that automaticaly grows as large as you need, instead of using an array that might turn out to be too small:
std::vector<int> v;
while(true) {
int t;
cin >> t;
if (t == 0) {
break;
}
v.push_back(t);
}
std::reverse(v.begin(),v.end());
That way, you don't have any sentinel values in your array / vector to begin with.
Note: Using the respective functions from the STL (std::reverse and std::find) is better, I was just guessing that you are bound to implement this on your own.
Step one: Write a proper reverse function. One that takes (a pointer to) the beginning as well as (a pointer to) the end of the range that should be reversed.
Step two: Write a function to find (the first position of) your sentinel in an array (given via beginning and end, again)
Step three: Connect the two: Reverse from the beginning to the position of your sentinel.
Example without templates:
void reverse(int * from, int * to) {
while ((to - from) > 1) {
--to;
int temp = *from;
*from = *to;
*to = temp;
++from;
}
}
int const * find(int const * from,
int const * const to,
int const value) {
while ((from != to) && (*from != value)) {
++from;
}
return from;
}
void reverse_until (int * const from,
int * const to,
int const sentinel) {
int const * const position_sentinel = find(from, to, sentinel);
reverse(from, from + (position_sentinel - from));
// return the sentinel position from this function
// if you want only the reversed part
}
Tested with:
int main() {
int test[10];
for (size_t i = 0; i < 10; ++i) {
test [i] = i + 1;
}
reverse_until (test, test + 10, 6);
copy(test, test + 10, ostream_iterator<int>{cout, " "});
return 0;
}
(live here)
You need to find the actual length of the array, before performing the reverse operation, and then use that length for all further operations.
Like this:
int actualArraySize = 0;
while(actualArraySize < arraysize && array[actualArraySize]!=0)
{
actualArraySize++;
}
int temp;
for (int i = 0; i < actualArraySize/2; i++)
{
temp = array[actualArraySize-1-i];
array[actualArraySize - i - 1] = array[i];
array[i] = temp;
}
cout << "The reverse array: ";
for (int i = 0; i < actualArraySize; i++)
cout << array[i]<< ' ';
cout << endl;
Note that, actualArraySize can be less than or equal to arraysize, but, not more than it, because of the condition in while(actualArraySize < arraysize && array[actualArraySize]!=0), which means that stop when either a 0 is found or the size of the array is reached.