Writing a custom std::next_permutation(string) function - c++

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

Related

How do I find the line number and line item number in a text file?

I need to find the line number and position number in the line with the specified character in the text file. I did this, but found the last symbol.
I have a task to find the fourth point "." from the end of the text file, how is this possible?
Text file:
One One
Two
....
Three
..
Three
Now I get the following result:
Line: 2
Pos: 6
What I have tried:
Check out my code (I'm looking for the first dot from the end of the file):
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main()
{
ifstream fin("t.txt");
string line;
int lines = 0;
int characters = 0;
int found_line = 0;
size_t found_pos = string::npos;
while (true)
{
if (!getline(fin, line)) break;
auto pos = line.find_last_of('.');
if (pos != string::npos)
{
found_line = lines;
found_pos = (characters + pos);
}
++lines;
characters += line.length();
}
if (found_pos != string::npos)
{
found_line = (lines - 0 - found_line); // line no, counting backwards from the bottom of the file
found_pos = (characters - 0 - found_pos); // pos of the 'first' dot, counting backwards from the end of the file
cout << "line " << found_line << "\n";
cout << "pos " << found_pos << "\n" + 1;
}
return 0;
}
In my comment, I sketched the following possible algorithm to solve OPs issue:
What you could do: While reading the file you can count the line numbers. Scan the line for one (or multiple) .s. The results can be stored in an array of 4 entries. (You have to manage an index for this.) For each found ., you store the line and inc. the index modulo 4 (e.g. i = (i + 1) % 4;. When you reached the end of file, the (i + 1) % 4 will contain the line for the 4th . from end. Of course, you also have to count that you found at least 4 .s (to handle edge cases).
Just for fun, I made an MCVE on coliru:
#include <array>
#include <fstream>
#include <iostream>
#include <string>
// (a kind of) ring buffer
template <typename V, int N>
struct RingT {
std::array<V, N> values;
int i = 0;
int n = 0;
void push(const V& value)
{
values[i++] = value;
if (i >= N) i = 0;
if (n < N) ++n;
}
int size() const { return n; }
const V& operator[](int j) const { return values[((i - 1 + j) % n + n) % n]; }
};
// text coordinates
struct Coord {
int line, col;
};
int main()
{
const int N = 4; // the number of occurrences (from end) to count
const char C = '.'; // the character to count occurrences for
// use (a kind of) ring buffer to store text coordinates
RingT<Coord, N> coords;
// scan file for occurrences of character C
#if 0 // OP
std::ifstream fIn("t.txt");
#else // for online check
std::ifstream fIn("main.cpp");
#endif // 0
int line = 1;
for (std::string buffer; std::getline(fIn, buffer); ++line) {
for (size_t col = 0;; ++col) {
col = buffer.find(C, col);
if (col < buffer.size()) coords.push({ line, (int)col });
else break;
}
}
// output result
if (coords.size() < N) {
std::cerr << "ERROR! File didn't contain " << N << " occurrences of '" << C << "'.\n";
} else {
const Coord& coord = coords[1]; // equivalent to coords[N - 1] -> it's a ring
std::cout << "The " << N << "th occurrence of '" << C << "' from end"
<< " was in line " << coord.line << ", col. " << coord.col << '\n';
}
}
Output:
The 4th occurrence of '.' from end was in line 52, col. 85
To simplify things on coliru, I used the source code main.cpp instead of t.txt. The online viewer of coliru displays line numbers. Hence, it's quite easy to check that the 4th occurrence of . from end is in fact in line 52. Line 52 is this one:
std::cerr << "ERROR! File didn't contain " << N << " occurrences of '" << C << "'.\n";
(I must admit that I didn't check the column but 85 looks reasonable.—There is a . near the end of line.)
The complete code is actually quite simple and straight-forward. The most convoluted thing is probably the RingT::operator[]:
const V& operator[](int j) const { return values[((i - 1 + j) % n + n) % n]; }
Thus, I'd like to dissect and explain it a bit:
There is given the index j as argument which should be looked up.
The index is relative to the last entry which was done: i - 1 + j.
The index is used modulo n to wrap around inside the buffer: (i - 1 + j) % n.
If i - 1 + j was a negative value then (i - 1 + j) % n becomes a negativ value as well. To fix this, n is added and then again modulo n: ((i - 1 + j) % n + n) % n.
This grants that the resulting index for array access will always be in the range [0, n). (Admittedly, possible integer overflow issues are ignored.)

Prevent loop from echoing if another same-value array element has been already echoed in C++

First of all, sorry for the mis-worded title. I couldn't imagine a better way to put it.
The problem I'm facing is as follows: In a part of my program, the program counts occurences of different a-zA-Z letters and then tells how many of each letters can be found in an array. The problem, however, is this:
If I have an array that consists of A;A;F;A;D or anything similar, the output will be this:
A - 3
A - 3
F - 1
A - 3
D - 1
But I am required to make it like this:
A - 3
F - 1
D - 1
I could solve the problem easily, however I can't use an additional array to check what values have been already echoed. I know why it happens, but I don't know a way to solve it without using an additional array.
This is the code snippet (the array simply consists of characters, not worthy of adding it to the snippet):
n is the size of array the user is asked to choose at the start of the program (not included in the snippet).
initburts is the current array member ID that is being compared against all other values.
burts is the counter that is being reset after the loop is done checking a letter and moves onto the next one.
do {
for (i = 0; i < n; i++) {
if (array[initburts] == array[i]) {
burts++;
}
}
cout << "\n\n" << array[initburts] << " - " << burts;
initburts++;
burts = 0;
if (initburts == n) {
isDone = true;
}
}
while (isDone == false);
Do your counting first, then loop over your counts printing the results.
std::map<decltype(array[0]), std::size_t> counts;
std::for_each(std::begin(array), std::end(array), [&counts](auto& item){ ++counts[item]; });
std::for_each(std::begin(counts), std::end(counts), [](auto& pair) { std::cout << "\n\n" << pair.first << " - " pair.second; });
for (i = 0; i < n; i++)
{
// first check if we printed this character already;
// this is the case if the same character occurred
// before the current one:
bool isNew = true;
for (j = 0; j < i; j++)
{
// you find out yourself, do you?
// do not forget to break the loop
// in case of having detected an equal value!
}
if(isNew)
{
// well, now we can count...
unsigned int count = 1;
for(int j = i + 1; j < n; ++j)
count += array[j] == array[i];
// appropriate output...
}
}
That would do the trick and retains the array as is, however is an O(n²) algorithm. More efficient (O(n*log(n))) is sorting the array in advance, then you can just iterate over the array once. Of course, original array sequence gets lost then:
std::sort(array, array + arrayLength);
auto start = array;
for(auto current = array + 1; current != array + arrayLength; ++current)
{
if(*current != *start)
{
auto char = *start;
auto count = current - start;
// output char and count appropriately
}
}
// now we yet lack the final character:
auto char = *start;
auto count = array + arrayLength - start;
// output char and count appropriately
Pointer arithmetic... Quite likely that your teacher gets suspicious if you just copy this code, but it should give you the necessary hints to make up your own variant (use indices instead of pointers...).
I would do it this way.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string s;
vector<int> capCount(26, 0), smallCount(26, 0);
cout << "Enter the string\n";
cin >> s;
for(int i = 0; i < s.length(); ++i)
{
char c = s.at(i);
if(c >= 'A' && c <= 'Z')
++capCount[(int)c - 65];
if(c >= 'a' && c <= 'z')
++smallCount[(int)c - 97];
}
for(int i = 0; i < 26; ++i)
{
if(capCount[i] > 0)
cout << (char) (i + 65) << ": " << capCount[i] << endl;
if(smallCount[i] > 0)
cout << (char) (i + 97) << ": " << smallCount[i] << endl;
}
}
Note: I have differentiated lower and upper case characters.
Here's is the sample output:
output

Shifting Objects Up in an Array

I'm creating a program that creates an array of objects in random positions in an array size 8. Once created, I need them to sort so that all the objects in the array are shifted up to the top, so no gaps exist between them. I'm almost there, but I cannot seem to get them to swap to index 0 in the array, and they instead swap to index 1. Any suggestions? (Must be done the way I'm doing it, not with other sorting algorithms or whatnot)
#include <iostream>
#include <string>
#include <ctime>
using namespace std;
struct WordCount {
string name = "";
int count = 0;
};
int main() {
cout << "Original random array: " << endl;
srand(static_cast<int>(time(0)));
int i = 0;
WordCount wordArr[8];
while (i < 4) {
int randomNum = 0 + (rand() % static_cast<int>(7 + 1));
if(wordArr[randomNum].name == "") {
wordArr[randomNum].name = "word" + static_cast<char>(i);
wordArr[randomNum].count = i;
i++;
}
}
int j = 0;
while (j < 8) {
cout << wordArr[j].name << " " << wordArr[j].count << endl;
j++;
}
cout << "\n\nSorted array: " << endl;
for (int i = 7; i >= 0; i--) {
for (int j = 0; j <= 7; j++) {
if (wordArr[i].name != "") {
if (wordArr[j].name == "") {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
}
int k = 0;
while (k < 8) {
cout << wordArr[k].name << " " << wordArr[k].count << endl;
k++;
}
return 0;
}
If I understand your requirement correctly, you want to move all the non-blank entries to the start of the array. To do this, you need an algorithm like this for example:
for i = 0 to 7
if wordArr[i].name is blank
for j = i + 1 to 7
if wordArr[j].name is not blank
swap [i] and [j]
break
So, starting from the beginning, if we encounter a blank entry, we look forward for the next non-blank entry. If we find such an entry, we swap the blank and non-blank entry, then break to loop again looking for the next blank entry.
Note, this isn't the most efficient of solutions, but it will get you started.
Note also I'd replace the 4 and 8 with definitions like:
#define MAX_ENTRIES (8)
#define TO_GENERATE_ENTRIES (4)
Finally:
wordArr[randomNum].name = "word" + static_cast<char>(i);
That will not do what you want it to do; try:
wordArr[randomNum].name = "word" + static_cast<char>('0' + i);
To append the digits, not the byte codes, to the end of the number. Or perhaps, if you have C++11:
wordArr[randomNum].name = "word" + std::to_string(i);
I see couple of problems.
The expression "word" + static_cast<char>(i); doesn't do what you are hoping to do.
It is equivalent to:
char const* w = "word";
char const* p = w + i;
When i is 2, p will be "rd". You need to use std::string("word") + std::to_string(i).
The logic for moving objects with the non-empty names to objects with empty names did not make sense to me. It obviously does not work for you. The following updated version works for me:
for (int i = 0; i <= 7; ++i) {
// If the name of the object at wordArr[i] is not empty, move on to the
// next item in the array. If it is empty, copy the next object that
// has a non-empty name.
if ( wordArr[i].name == "") {
// Start comparing from the object at wordArr[i+1]. There
// is no need to start at wordArr[i]. We know that it is empty.
for (int j = i+1; j <= 7; ++j) {
if (wordArr[j].name != "") {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
}
There was two problems as :
wordArr[randomNum].name = "word" + static_cast<char>(i); this is not what your are looking for, if you want that your names generate correctly you need something like this :
wordArr[randomNum].name = "word " + std::to_string(i);
Your sorting loop does not do what you want, it's just check for the "gaps" as you said, you need something like this :
for (int i = 0; i < 8; ++i) {
for (int j = i+1; j < 8; ++j) {
if (wordArr[i].name == "" || (wordArr[i].count < wordArr[j].count)) {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
}
}
}
Your algorithm sorts the array, but then looses the sorting again.
You want to swap elements only when i > j, in order to push elements to the top only. As a result, you need to change this:
if (wordArr[j].name == "")
to this:
if (wordArr[j].name == "" && i > j)
Consider this array example:
0
ord 1
0
0
rd 2
word 0
d 3
0
Your code will sort it to:
d 3
ord 1
word 0
rd 2
0
0
0
0
but when i = 3, it will try to populate the 5th cell, and it will swap it with rd 2, which is not what we want.
This will push rd 2 down, but we don't want that, we want gaps (zeroes) to go to the end of the array, thus we need to swap eleemnts only when they are going to go higher, not lower, which is equivalent to say when i > j.
PS: If you are a beginner skip that part.
You can optimize the inner loop by using one if statement and a break keyword, like this:
for (int j = 0; j <= 7; j++) {
if (wordArr[i].name != "" && wordArr[j].name == "" && i > j) {
WordCount temp = wordArr[i];
wordArr[i] = wordArr[j];
wordArr[j] = temp;
break;
}
}

Binary search not working for n = 1, 2

This is my code for binary search, and n = no of elements in array
// Binary Search
// BUG: not working for n = 2
#include <iostream>
int main() {
const int n = 1;
int newlist[n];
std::cout << "Enter " << n;
std::cout << " elements in increasing order:\n";
for( int i = 0; i < n; ++i ) {
std::cin >> newlist[i];
}
int pos = 0, num;
std::cout << "Enter number:\n";
std::cin >> num;
std::cout << '\n';
int imin = 0, imax = n-1;
int imid = (n - 1)/2;
for( int i = 0; i < n; ++i ) {
imid = (imin + imax) / 2;
if( newlist[imid] == num ) {
pos = imid;
}
else if( newlist[imid] < num ) {
imin = imid+1;
}
else {
imax = imid-1;
}
}
if( pos != 0 ) {
std::cout << "Found at " << pos+1;
}
else {
std::cout << "Not found!\n";
}
return 0;
}
It does work for n > 2, but fails to give correct output for n <= 2, ie, gives Not found! output even for elements that were found.
I think one way would be to have a separate implementation for n <= 2, but that will become cumbersome! Please help.
Set your pos operator to -1 rather than 0. 0 represents your first index and since you output that the element has not been found for pos == 0 condition, your code is failing. You should set pos to -1 initially and check that itself for not found condition, if an element is found at pos = 0, that means the element exists at the first index.
First pos equal to 0 is correct value. Therefore set pos to -1 at the beginning and compare to -1 (or more commonly >= 0) when checking whether it was found.
Secondly, there are few items that should be changed because right now it's not that much binary search:
There is no reason to initialize mid before the loop, it's just temporary variable with the scope in loop block.
The condition for exiting the search is min > max, you don't need any additional counter, as it would run the loop always n times even if the value didn't exist. So change to while (min <= max) { ...
Last but not least, once you find the item, exit the loop immediately by break statement.
I don't think a for-loop is the control structure to go for here, because you want to finish when you've either found the correct item or when imin and imax are non-sensical.
In the implementation given, you don't even stop the loop when you have found the item and just confirm the found item "n-(number of iterations until item was found)" times.
Furthermore, with C++ arrays and vectors being 0-based, having position == 0 as the marker for "not found" is a bad idea; you could instead use an item from http://en.cppreference.com/w/cpp/types/numeric_limits, or n (since the indices go from 0 to n-1).
In theory, you could use pointer arithmetic to make your array 1-based, and I am assuming you haven't; I wouldn't recommend it. However, you're code snipped is missing the actual definition of the list.

C++, moving a NaN to the end of the array, when output

So, i've made a program which is able to sort arrays, and i'm trying to sort an array containing double FP's, including 2-3 random ones i enter, pos inf, neg inf and a single NaN. so for this purpose i wish to sort the NaN.
So my code works, however when trying to sort the NaN, i'm unable to do so. What i'd like to do is sort it to the end, or have it put at the end of the sorted array. Is there anyway I can actually do this? Thanks in advance!!! code is as follows:
int main()
{
int start_s = clock();
int n, k = 4, j; // k is number of elements
double x = -0.0;
double i = 0;
double swap = 0;//used in the function as a place holder and used for swapping between other variables
double a[100] = { (1/x) + (1/i), 2.3, 1/x *0, 1/i };//array of double elements // 1/i * 0 is NaN
//(1 / i) * 0
for (n = 0; n < (k - 1); n++) // for loop consists of variables and statements in order to arrange contents of array
{
for (j = 0; j < k - n - 1; j++)
{
if (a[j] > a[j + 1])
{
swap = a[j];
a[j] = a[j + 1];
a[j + 1] = swap;
}
}
}
cout << "The list of sorted elements within the array, is: " << endl; /* Output message to user */
for (int i = 0; i < k; i++)// Loop up to number of elements within the array
{
cout << a[i] << " ";/* Output contents of array */
}
cout << endl; //new line
int stop_s = clock();
cout << "The execution time of this sort, is equal to: " << (stop_s - start_s) / double(CLOCKS_PER_SEC) * 1000 << " milliseconds" << endl;
return 0;
Since you're in C++ land anyway, why not use it to the full. First, indeed, move the NaN's and then sort. I've taken out 'noise' from your code and produced this, it compiles and runs (edit: on gcc-4.4.3). The main difference is that the NaN's are at the beginning but they're easily skipped since you will get a pointer to the start of non-NaN's.
#include <iostream>
#include <algorithm>
#include <math.h>
int main()
{
int n, k = 4, j; // k is number of elements
double x = -0.0;
double i = 0;
double a[100] = { (1/x) + (1/i), 2.3, 1/x *0, 1/i };//array of double elements // 1/i * 0 is NaN]
double *ptr; // will point at first non-NaN double
// divide the list into two parts: NaN's and non-NaN's
ptr = std::partition(a, a+k, isnan);
// and sort 'm
// EDIT: of course, start sorting _after_ the NaNs ...
std::sort(ptr, a+k);
cout << "The list of sorted elements within the array, is: " << endl; /* Output message to user */
for (int i = 0; i < k; i++)// Loop up to number of elements within the array
{
cout << a[i] << " ";/* Output contents of array */
}
cout << endl; //new line
return 0;
}
Do a linear scan, find the NaNs, and move them to the end - by swapping.
Then sort the rest.
You can also fix your comparator, and check for NaN there.
For the actual check see: Checking if a double (or float) is NaN in C++
you can use isnan() in cmath to check for NaNs. So, you can just change your comparison line from:
if (a[j] > a[j + 1])
to:
if (!std::isnan(a[j + 1]) && std::isnan(a[j]) || (a[j] > a[j + 1]))
just a reminder, you need to have:
#include <cmath>
at the top of your code.