C++ shift values to begin of array - c++

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.

Related

Writing a custom std::next_permutation(string) function

I am trying to implement a function similar to std::next_permutation(std::string w). Please see the code below for how I am doing this:
string biggerIsGreater(string w) {
// 1. Find the largest non-increasing suffix. This suffix already has the maximum permutation.
// 2. Assign the char before that as the pivot
// if there is no such char,
// then the whole string is non-increasing => no next permutation.
// 3. Swap the pivot with the smallest element in the suffix that is greater than the pivot itself.
// If there are multiple smallest char > pivot, then choose the rightmost one
// As this will keep the suffix non-increasing.
// 4. reverse the order of the suffix, so that it is now non-decreasing.
// This is the lowest next permutation.
// 1.
int suffix_start = (int)w.length()-1;
//single character has no next permutation:
if (suffix_start == 0) return "no answer";
// else keep decreasing suffix_start until the element is not > the previous.
while(w[suffix_start-1] <= w[suffix_start]) {
suffix_start--;
if(suffix_start==0) return "no answer";
}
// 2.
int pivot = suffix_start - 1;
// 3.
int smallest_char = (int)w.length()-1;
while(w[smallest_char] <= w[pivot]) smallest_char--;
if(w[smallest_char] == w[smallest_char-1]) while (w[smallest_char] != w[smallest_char-1]) smallest_char--;
swap(w[pivot], w[smallest_char]);
// 4.
reverse(w.begin() + pivot + 1, w.end());
return w;
}
However, this code appears to fail on strings like bb. Please can you tell me where I have gone wrong?
If I print out w after the reversal, I get this: (the first line is the number of test cases):
input:
5
ab
bb
hefg
dhck
dkhc
Then the program prints ba (which means the first one worked) but nothing else is printed.
So the error is in dealing with bb.
Note: My objective is to write this without std::next_permutation() function from <algorithm>.
I re-implemented your function my own way, if it is not an acceptable answer, then at least it is benefitial for educational purpose. Maybe by my code you can figure out what's wrong in yours.
If this is last permutation, like "bb" case then first lexicographical permutation is returned, same as in std::next_permutation().
Try it online!
#include <algorithm>
#include <iostream>
#include <string>
std::string next_permutation(std::string x) {
if (x.size() <= 1)
return x;
std::ptrdiff_t i = 0, j = 0;
for (i = x.size() - 2; i >= 0 && x[i] >= x[i + 1]; --i);
if (i >= 0) {
for (j = i + 1; j < x.size() && x[i] < x[j]; ++j);
--j;
std::swap(x[i], x[j]);
}
std::reverse(x.begin() + (i + 1), x.end());
return x;
}
int main() {
auto Test = [](auto const & s){
std::cout << "'" << s << "' -> '"
<< next_permutation(s) << "'" << std::endl;
};
Test("ab");
Test("bb");
Test("hefg");
Test("dhck");
Test("dkhc");
Test("abc");
Test("aabb");
Test("cba");
}
Output:
'ab' -> 'ba'
'bb' -> 'bb'
'hefg' -> 'hegf'
'dhck' -> 'dhkc'
'dkhc' -> 'hcdk'
'abc' -> 'acb'
'aabb' -> 'abab'
'cba' -> 'abc'
This is #Arty's solution. So full credit to him.
I added comments to try and explain how it works so that I can understand it better.
#include <string>
#include <iostream>
#include <algorithm>
std::string next_permutation(std::string x) {
std::ptrdiff_t i = 0, j = 0;
// start with penultimate element
// as long as i doesn't hit the start and the sequence is non-increasing, keep decreasing i.
// the value of i we reach is the first element from the right which is not in reverse order (=> the maximum permutation)
// this is the pivot
for (i = x.size() - 2; i >= 0 && x[i] >= x[i + 1]; --i);
// if the whole array is reverse order, there is no maximum permutation.
if (i < 0)
return {};
// then find the first element after i which is less than x[i].
for (j = i + 1; j < x.size() && x[i] < x[j]; ++j);
// stop at the next element -- I like this as it avoids the problem of acccb, if a is the pivot
// then this code will stop at the first c.
--j;
// swap the elements
std::swap(x[i], x[j]);
// reverse the remaining array in order to minimise it, as we know it is in descending order.
std::reverse(&x[i + 1], &x[x.size()]);
return x;
}
int main() {
auto Test = [](auto const& s) {
std::cout << "'" << s << "' -> '"
<< next_permutation(s) << "'" << std::endl;
};
Test("abc");
Test("bb");
Test("aabb");
Test("cba");
}

Binary Search function that displays all matching values?

I have an assignment that requires me to create a binary search function that will search an array of structs that contain dates for a specified month and then print all of those entries with matching months.
I am having a very difficult time getting the binary search to work properly when I am searching for multiple values, and can't seem to figure out where I'm going wrong.
Here is my binary search function:
void binsearch(Event* ev_ptr[], int size, int month)
{
int low = 0, high = size - 1, first_index = -1, last_index = -1;
while (low <= high) //loop to find first occurence
{
int mid = (low + high) / 2;
if (ev_ptr[mid]->date.month < month)
{
low = mid + 1;
}
else if (ev_ptr[mid]->date.month > month)
{
first_index = mid;
high = mid - 1;
}
else if (ev_ptr[mid]->date.month == month)
{
low = mid + 1;
}
}
low = 0; high = size - 1; //Reset so we can find the last occurence
while (low <= high) //loop to find last occurence
{
int mid = (low + high) / 2;
if (ev_ptr[mid]->date.month < month)
{
last_index = mid;
low = mid + 1;
}
else if (ev_ptr[mid]->date.month > month)
{
high = mid - 1;
}
else if (ev_ptr[mid]->date.month == month)
{
high = mid + 1;
}
}
for (int i = first_index; i <= last_index; i++)
{
cout << "\nEntry found: "
<< endl << ev_ptr[i]->desc
<< endl << "Date: " << ev_ptr[i]->date.month << '/' << ev_ptr[i]->date.day << '/' << ev_ptr[i]->date.year
<< endl << "Time: " << setw(2) << setfill('0') << ev_ptr[i]->time.hour << ':' << setw(2) << setfill('0') << ev_ptr[i]->time.minute << endl;
}
}
and here is my main function:
const int MAX = 50;
int main()
{
Event* event_pointers[MAX];
int count, userMonth;
char userString[80];
count = readEvents(event_pointers, MAX);
sort_desc(event_pointers, count);
display(event_pointers, count);
cout << "\n\nEnter a search string: ";
cin.getline(userString, 80, '\n');
cin.ignore();
linsearch(event_pointers, count, userString);
sort_date(event_pointers, count);
display(event_pointers, count);
cout << "\n\nEnter a month to list Events for: ";
cin >> userMonth;
cin.ignore();
binsearch(event_pointers, count, userMonth);
for (int j = 0; j < count; j++) //Cleanup loop
delete event_pointers[j];
cout << "\nPress any key to continue...";
(void)_getch();
return 0;
}
I've gotten everything else to work as I need to for this assignment, but it's just this binary search that seems to be causing problems. I have tried using some things I found online in the most recent iteration (What I posted above), but to no avail. Any help would be greatly appreciated!
Don't set theses indices with binsearch. Search for an occurence than loop downwards and upwards until the conditions fails. Something like
else if (ev_ptr[mid]->date.month == month)
{
// mid = some occurence found
// increment and decrement mid until condition fails
}```
To design correct binary search function, don't try to guess the solution, it's hard to get it right. Use the method of loop invariants. The function that finds the first occurrence is called lower_bound in the standard library, so let's use this name here, too:
template<class It, typename T>
It lower_bound(It first, std::size_t size, const T& value);
Let's introduce the last variable: auto last = first + size. We will be looking for a transition point pt, such that in the range [first, pt), all elements have values < value, and in the range [pt, last), all elements have values >= value. Let's introduce two iterators (pointers) left and right with the loop invariants:
in the range [first, left) all elements have values < value,
in the range [right, last) all elements have values >= value.
These ranges represent elements examined so far. Initially, left = first, and right = last, so both ranges are empty. At each iteration one of them will be expanded. Finally, left = right, so the whole range [first, last) has been examined. From the definitions above, it follows that pt = right.
The following algorithm implements this idea:
template<class It, typename T>
It lower_bound(const It first, const std::size_t size, const T& value) {
const auto last = first + size;
auto left = first;
auto right = last;
while (left < right) {
const auto mid = left + (right - left) / 2;
if (*mid < value) // examined [first, left)
left = mid + 1;
else // examined [right, last)
right = mid;
}
return right;
}
Here we can reuse variables first and last to represent left and right. I didn't do it for clarify.
Now let's analyze your implementation. I can infer the following loop invariants:
[first, low) - all elements have values < value,
(high, last) - all elements have values >= value.
These are the same invariants, with right being replaced with high + 1. The while loop itself is correct, but the condition, which can be rewritten as
if (*mid <= value)
low = mid + 1;
else {
first_index = mid;
high = mid - 1;
}
is broken. With this condition, the range [first, low) will contain all elements with values <= value. This corresponds to the upper_bound. The comparison should be <, not <=.
You can analyse the second loop in the same way. In that loop at least one assignment of mid is incorrect.
int mid = (low + high) / 2;
...
high = mid + 1;
...
This is potentially an infinite loop. If high = low + 1, then mid = low, and you set high to mid + 1 = high. You modify neither low, nor high, and the loop becomes infinite.
The first approach, with two half-open ranges is beneficial IMO. It is symmetrical and is easier to reason about. If no value has been found, last = first + size is returned, which is a natural choice to represent the end of the range. You should check for first_index and last_index after the loops. What if they have not been reassigned and still hold -1?
1 Define you struct as this example,
struct element {
YourDate date;
...
operator int() const { return date.month;}
};
2 Sort elements as,
std::sort(elements.begin(), elements.end(), std::less<int>());
3 use
std::equal_range(elements.begin(), elements.end(), your_target_month);
4 print what you get from std::equal_range

Taking pairs of numbers representing begin/end, and removing overlaps

I have an array of pairs that represent a range of [begin,end). The array can be assumed to already sorted by the 'begin' field.
I want to generate a new array with all of the overlaps removed, and additional pairs created, as needed.
For example, let's say the array contained the following pairs:
[1,3],[2,5],[7,15],[8,9],[12,19]
The output should be as follows:
[1,2],[2,3],[3,5],[7,8],[8,9],[9,12],[12,15],[15,19]
Ultimately, the output array should contain no overlaps at all.
What's the most optimal solution that takes no more than O(m), where m is the number of entries needed in the output array? I think I see a way to do it in O(n^2), where n is the number of entries in the input array, but there's got to be a better way.
The final implementation will be in C++11, using vectors of pairs of doubles, although pseudocode solutions are fine.
EDIT:
I appreciate all responses, but I would politely request in advance to please not post any solutions that depend on particular frameworks or libraries unless such frameworks are part of standard c++11.
First I'll solve a related problem; generate merged intervals that cover the same area with no adjacency or overlap.
Walk the input array. Start with the first element. Record highwater (end of interval) and lowater (start of interval).
Proceed forward. Each element, if it overlaps the interval, extend highwater. If not, output highwater and lowater as an interval, then record a new high and lowater.
This takes O(n) time on input.
Every element of input must be read, because any of them could go from their start location to the end and change the result. So this is O-optimal.
This merges intervals into the largest contiguous one you can make; you want to save all of the "edges" or "seams" in the original intervals. To solve your spec, simply keep track of seams (in order) and break the generated intervals at those seams. "Lowater" seams will always come with increasing values; highwater seams may not. So an ordered set of seams should work. This is O(nlgn) sadly due to the set.
// half open
struct interval {
int lowater = 0;
int highwater = 0;
bool empty() const {
return lowater == highwater;
}
friend std::ostream& operator<<( std::ostream& os, interval i ) {
return os << "[" << i.lowater << "," << i.highwater << "]";
}
};
template<class Range, class Out>
void build_intervals( Range&& in, Out out ) {
std::optional<interval> current;
std::set<int> seams;
auto dump_interval = [&](interval i){
if (i.empty()) return;
*out = i;
};
auto dump_current = [&]{
if (!current) return;
// std::cout << "Dumping " << *current << " with seams: {";
for (int seam:seams) {
// std::cout << seam << ",";
dump_interval({ current->lowater, seam });
current->lowater = seam;
}
// std::cout << "}\n";
dump_interval( *current );
current = std::nullopt;
seams.clear();
};
for (auto&& e : in) {
if (current && e.lowater <= current->highwater) {
seams.insert(e.lowater);
seams.insert(e.highwater);
// std::cout << "No gap between " << *current << " and " << e << "\n";
current->highwater = (std::max)(e.highwater, current->highwater);
// std::cout << "Combined: " << *current << "\n";
continue;
}
if (!current) {
// std::cout << "New current " << e << "\n";
} else {
// std::cout << "Gap between " << *current << " and " << e << "\n";
dump_current();
}
current = e;
seams.insert(e.lowater);
seams.insert(e.highwater);
}
dump_current();
}
live example.
I came up with something like this, by adding just couple of if it is done in O(n) time. I'm just not sure about last elements, my output:
[1 : 2], [2 : 3], [3 : 5], [7 : 8], [8 : 9], [9 : 12], [12 : 15], [15 : 19]
Maybe its something that would help:
std::vector<std::pair<int, int>> noOverlaps(std::vector<std::pair<int, int>>& input) {
if (input.size() <= 1) {
return input;
}
std::vector<std::pair<int, int>> result;
result.push_back(input[0]);
for (int i = 1; i < input.size(); ++i) {
//If overlap
if (input[i].first < result.back().second) {
auto lastOne = result.back();
result.pop_back();
result.push_back(std::make_pair(lastOne.first, input[i].first));
if (lastOne.second > input[i].second) {
result.push_back(std::make_pair(input[i].first, input[i].second));
result.push_back(std::make_pair(input[i].second, lastOne.second));
} else {
result.push_back(std::make_pair(input[i].first, lastOne.second));
result.push_back(std::make_pair(lastOne.second, input[i].second));
}
} else {
result.push_back(input[i]);
}
}
return result;
}
Update 1
As pointed out in the comment above will not work with multiple overlapping intervals, so the above solution can be improved by swallowing intervals that are containing each other and run the same algorithm:
std::vector<std::pair<int, int>> noOverlaps(std::vector<std::pair<int, int>>& origInput) {
if (origInput.size() <= 1) {
return origInput;
}
std::vector<std::pair<int, int>> result;
std::vector<std::pair<int, int>> input;
input.push_back(origInput[0]);
for (int i = 1; i < origInput.size(); ++i) {
if (input[i-1].first <= origInput[i].first && input[i-1].second >= origInput[i].second) {
continue;
}
input.push_back(origInput[i]);
}
result.push_back(input[0]);
for (int i = 1; i < input.size(); ++i) {
//If overlap
if (input[i].first < result.back().second) {
auto lastOne = result.back();
result.pop_back();
result.push_back(std::make_pair(lastOne.first, input[i].first));
if (lastOne.second > input[i].second) {
result.push_back(std::make_pair(input[i].first, input[i].second));
result.push_back(std::make_pair(input[i].second, lastOne.second));
} else {
result.push_back(std::make_pair(input[i].first, lastOne.second));
result.push_back(std::make_pair(lastOne.second, input[i].second));
}
} else {
result.push_back(input[i]);
}
}
return result;
}
But this requires 2xO(n) space complexity and code is not nice.
So I just wonder would that not be enough:
std::vector<std::pair<int, int>> noOverlaps2(std::vector<std::pair<int, int>>& origInput) {
if (origInput.size() <= 1) {
return origInput;
}
int low = origInput[0].first, high = origInput[0].second;
std::vector<std::pair<int, int>> result;
for (int i = 1; i < origInput.size(); ++i) {
if (high < origInput[i].first) {
result.emplace_back(low, high);
low = origInput[i].first;
high = origInput[i].second;
} else {
high = std::max(origInput[i].second, high);
}
}
result.emplace_back(low, high);
return result;
}
For your data it gives output:[1 : 5], [7 : 19] but it get rid of overlaps.

Reverse Array with given sentinel value

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.

Quicksort algorithm not functioning properly

#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); } }