How to generate a set of unique hash strings in C++? - c++

This code produce 26*26*26*26 hasname (using combinations of a-z)or you can say random names which i want to assign to a structure member.Now when i am assigning that by first allocating that structure member sufficient memory and then using strcpy, only last hashname generated by this code is being passed to the structure i.e zzzz(it is the last hashname).What can i do so that hashname is assigned from the starting.
vcd_xyz[4] = '\0';
int count = 0;
for(int i=0;i<26;i++)
{
vcd_xyz[0] = 'a'+i;
for(int j=0;j<26;j++)
{
vcd_xyz[1] = 'a'+j;
for(int k = 0;k<26;k++)
{
vcd_xyz[2] = 'a' + k;
for(int l=0;l<26;l++)
{
vcd_xyz[3] = 'a' +l;
count ++;
printf("%s\n",vcd_xyz);
}
}
}
}
So i am using
sss->Variables[0].hashname = (char*)calloc(strlen((char*)vcd_xyz)+1,sizeof(char));
strcpy(sss->Variables[0].hashname,(char*)vcd_xyz);
to copy the hasname produced but it is copying the last hashname produced, so where ever i am using tr0->Variables[0].hashname = (char*)calloc(strlen((char*)vcd_xyz)+1,sizeof(char));
strcpy(tr0->Variables[0].hashname,(char*)vcd_xyz); only zzzz get printed.what i am doing wrong or what should i do so that hashname are assigned in a sequential manner.

At first you need to realize that char vcd_xyz[4] is an array of 4 characters, meaning that you can put there 3 characters + terminating character '\0'. If you treat this array as it is null-terminated when it is not, it results in undefined behavior.
What your code actually does is that it iterates through all possible combinations of 4 letters long strings, from "aaaa" to "zzzz", leaving the vcd_xyz array filled with the last combination (i.e. "zzzz").
If you want to generate random 4-letters long string, here's the C-style function you might use:
int irand(int min, int max) {
return ((double)rand() / ((double)RAND_MAX + 1.0)) * (max - min + 1) + min;
}
it generates random number from <min;max> interval and it can be used like this:
std::string generateHashTag() {
char str[5];
for (int i = 0; i < 4; ++i)
str[i] = irand('a', 'z');
str[4] = '\0';
return std::string(str);
}
But in case you want to generate a set of unique 4-letters long hash tags, you will need more complex solution. In C++ you might easily generate these strings in a loop that will put them into an std::set container till you have enough of them or you might generate more unique combinations of this string, put all of these into an std::vector, shuffle it and pick first N, e.g.:
const size_t N = 5;
std::set<std::string> myHashTags;
srand(time(0));
while (myHashTags.size() < N)
myHashTags.insert(generateHashTag());
for (std::set<std::string>::iterator i = myHashTags.begin();
i != myHashTags.end(); ++i)
std::cout << *i << ' ';
outputs kemy snwv vnmi wfmm wqeg. Full example here.

Related

Determine duplicates/pairs in an array in C++

I have been doing this problem for 2 days now, and I still can't figure out how to do this properly.
In this program, I have to input the number of sticks available (let's say 5). Then, the user will be asked to input the lengths of each stick (space-separated integer). Let's say the lengths of each stick respectively are [4, 4, 3, 3, 4]. Now, I have to determine if there are pairs (2 sticks of same length). In this case, we have 2 (4,4 and 3,3). Since there are 2 pairs, we can create a canvas (a canvas has a total of 2 pairs of sticks as the frame). Now, I don't know exactly how to determine how many "pairs" there are in an array. I would like to ask for your help and guidance. Just note that I am a beginner. I might not understand complex processes. So, if there is a simple (or something that a beginner can understand) way to do it, it would be great. It's just that I don't want to put something in my code that I don't fully comprehend. Thank you!
Attached here is the link to the problem itself.
https://codeforces.com/problemset/problem/127/B
Here is my code (without the process that determines the number of pairs)
#include<iostream>
#include<cmath>
#define MAX 100
int lookForPairs(int numberOfSticks);
int main(void){
int numberOfSticks = 0, maxNumOfFrames = 0;
std::cin >> numberOfSticks;
maxNumOfFrames = lookForPairs(numberOfSticks);
std::cout << maxNumOfFrames << std::endl;
return 0;
}
int lookForPairs(int numberOfSticks){
int lengths[MAX], pairs = 0, count = 0, canvas = 0;
for(int i=0; i<numberOfSticks; i++){
std::cin >> lengths[i];
}
pairs = floor(count/2);
canvas = floor(pairs/2);
return count;
}
I tried doing it like this, but it was flawed. It wouldn't work when there were 3 or more integers of the same number (for ex. [4, 4, 3, 4, 2] or [5. 5. 5. 5. 6]). On the first array, the count would be 6 when it should only be 3 since there are only three 4s.
for(int i=0; i<numberOfSticks; i++){
for (int j=0; j<numberOfSticks; j++){
if (lengths[i] == lengths[j] && i!=j)
count++;
}
}
Instead of storing all the lengths and then comparing them, count how many there are of each length directly.
These values are known to be positive and at most 100, so you can use an int[100] array for this as well:
int counts[MAX] = {}; // Initialize array to all zeros.
for(int i = 0; i < numberOfSticks; i++) {
int length = 0;
std::cin >> length;
counts[length-1] += 1; // Adjust for zero-based indexing.
}
Then count them:
int pairs = 0;
for(int i = 0; i < MAX; i++) {
pairs += counts[i] / 2;
}
and then you have the answer:
return pairs;
Just an extension to molbdnilo's answer: You can even count all pairs in one single iteration:
for(int i = 0; i < numberOfSticks; ++i)
{
if(std::cin >> length) // catch invalid input!
{
pairs += flags[length] == 1; // add a pair if there is already a stick
flags[length] ^= 1; // toggle between 0 and 1...
}
else
{
// some appropriate error handling
}
}
Note that I skipped subtracting 1 from the length – which requires the array being one larger in length (but now it can be of smallest type available, i.e. char), while index 0 just serves as an unused sentinel. This variant would even allow to use bitmaps for storing the flags, though questionable if, with a maximum length that small, all this bit fiddling would be worth it…
You can count the number of occurrences using a map. It seems that you are not allowed to use a standard map. Since the size of a stick is limited to 100, according to the link you provided, you can use an array, m of 101 items (stick's minimum size is 1, maximum size is 100). The element index is the size of the stick. The element value is the number of sticks. That is, m[a[i]] is the number of sticks of size a[i]. Demo.
#define MAX 100
int n = 7;
int a[MAX] = { 1,2,3,4,1,2,3 };
int m[MAX + 1]; // maps stick len to number of sticks
void count()
{
for (int i = 0; i < n; ++i)
m[a[i]]++;
}
int main()
{
count();
for (int i = 1; i < MAX + 1; ++i)
if (m[i])
std::cout << i << "->" << m[i] << std::endl;
}
Your inner loop is counting forward from the very beginning each time, making you overcount the items in your array. Count forward from i , not zero.
for(int i=0; i<numberOfSticks; i++)
{
for (int j=i; j<numberOfSticks; j++) { // count forward from i (not zero)
if (lengths[i] == lengths[j] && i!=j)
{ // enclosing your blocks in curly braces , even if only one line, is easier to read
count++; // you'll want to store this value somewhere along with the 'length'. perhaps a map?
}
}
}

Why is my c++ sorting function so much slower than my c# sorting function?

I'm very new to c++, but I do have experience with other object oriented programming languages.
I'm attempting to alphabetically sort the lines in a file I have, which has roughly 5300 lines. I originally wrote the program in c++ for practice, but was curious to see how it would perform against my main language, c#.
To my surprise, the same sorting algorithm which takes my c++ function 18-20 seconds to execute, finishes in less than 3 seconds in c#.
Given that I am very new to c++ (and not a very experienced programmer in general), I am sure this must be an error in the way I wrote something.
With all that being said, I am aware that there are quicker sorting methods to use. However, both programs are using the same algorithm so I don't understand the reason for the large performance gap.
I will note that I have tried converting the data to an array instead of a vector, but sorting the array was only consistently about 3 seconds faster (about 15 seconds total instead of 18).
What am I doing wrong? Any/all help is appreciated!
Below is the c++:
void select_sort_alphabetical(std::vector<std::string> _vector)
{
std::cout << "<< SORTING... >>" << "\n\n";
int char_index, i, j, size = _vector.size(), loop_iterations = 0;
char char1, char2;
std::string temp;
// Iterate through all lines
for (i = 0; i < (size - 1); i++)
{
for (j = (1 + i); j < size; j++)
{
char_index = 0;
char1 = _vector[i][char_index]; // Getting first character of each line
char2 = _vector[j][char_index];
// While the letters to be compared are the same, move onto the next character
while (char1 == char2)
{
char_index++;
char1 = _vector[i][char_index]; // Setting chars to the next characters in each line
char2 = _vector[j][char_index];
}
// Once the characters are different - if line x.ascii_code greater than line x+1.ascii_code...
if (_vector[i][char_index] > _vector[j][char_index]) // comparing characters
{
// Swapping places
temp = _vector[i];
_vector[i] = _vector[j];
_vector[j] = temp;
}
loop_iterations++;
}
}
//print_lines_from_vect(_vector);
// Clearing contents of vector and freeing up memory (trying to, anyway)
_vector.clear();
_vector.shrink_to_fit();
std::cout << "\nIterations: " << loop_iterations << "\n";
}
and here is the c#:
public static string[] select_sort_alphabetical(string[] lines, ref int loop_iterations)
{
Console.WriteLine("<< SORTING... >>");
// Iterate through all lines
for (int i = 0; i < (lines.Length - 2); i++)
{
for (int j = (1 + i); j < (lines.Length); j++)
{
int char_index = 0;
char char1 = lines[i][char_index]; // Getting first character of each line
char char2 = lines[j][char_index];
// While the letters to be compared are the same, move onto the next character
while (char1 == char2)
{
char_index++;
char1 = lines[i][char_index];
char2 = lines[j][char_index];
}
// Once the characters are different - if line x.ascii_code greater than line x+1.ascii_code...
if (lines[i][char_index] > lines[j][char_index]) // comparing characters
{
// Swapping places
string temp = lines[i];
lines[i] = lines[j];
lines[j] = temp;
}
loop_iterations++;
}
}
return lines;
}
One reason your algorithm would be slower, without taking in account other differences between languages, is swapping lines:
// Swapping places
string temp = lines[i];
lines[i] = lines[j];
lines[j] = temp;
in c#, string temp = original means temp and original point to the same string. modifying each will reflect in the other.
in c++, string temp = original means temp is a new string. Modifying one will not modify the other.
C++ provides move class members, which allow new objects to "steal" the resources of the original object.
std:.swap, in order to swap objects, make something like
string temp = steal(lines[i]);
lines[i] = steal(lines[j]);
lines[j] = steal(temp);
This is a simplification of the real mechanism.
Btw, if you use swap, you will see far faster debug, because that line swapping is a big cost in your algorithm.

looking for a faster way to help reduce/create a huge list of strings

I tried to write an algorithm to guess correctly in the game "Masterminds",
it works the average number of guesses is 6, but it takes a lot of time to calculate the best guess.
I used the idea of Knuth the algorithm works as follows:
Create the set S of 1296 possible codes (1111, 1112 ... 6665, 6666).
Start with initial guess 1122 (Knuth gives examples showing that other first guesses such as 1123, 1234 do not win in five tries on
every code).
Play the guess to get a response of colored and white pegs.
If the response is four colored pegs, the game is won, the algorithm terminates.
Otherwise, remove from S any code that would not give the same response if the current guess were the code.
In my code step 2 is to take random number.
I used vector<string> for this.
AllPoss is the vector full of strings, I guess is the last guess that was used. answer is the count of bulls and cows looks like "x,y" (where x and y are numbers)
void bullpgia::SmartGuesser::remove(string guess, string answer)
{
for (auto i= AllPoss.begin();i != AllPoss.end();i++){
string token = *i;
if (calculateBullAndPgia(token, guess) != answer)
AllPoss.erase(i--);
}
}
this is the part it take a lot of time to calculate is there any way of improvement?
to creating the list i used :
void bullpgia::SmartGuesser::All() {
/**
* creates a pool of all the possibilities strings
* we then delete the ones we dont need
* #param length is the length of the word we need to guess
*/
for(int i=0;i<pow(10,length);i++){
stringstream ss;
ss << setw(length) << setfill('0') << i;
string s = ss.str();
AllPoss.push_back(s);
}
}
the function calculateBullAndPgia(string , string) is:
string calculateBullAndPgia(const string &choice, const string &guess) {
string temp = choice;
string temp2 = guess;
unsigned int bull = 0;
unsigned int pgia = 0;
for (int i = 0; i < temp.length(); i++) {
if (temp[i] == temp2[i]) {
bull++;
temp[i] = 'a';
temp2[i] = 'z';
}
}
for (int i = 0; i < temp.length(); i++) {
for (int j = 0; j < temp2.length(); j++) {
if (i != j && temp[i] == temp2[j]) {
pgia++;
temp[i] = 'a';
temp2[j] = 'z';
}
}
}
return to_string(bull) + "," + to_string(pgia);
}
Erasing a single element in the middle of a vector is O(n). My guess is that you wind up doing it O(n) times per call to SmartGuesser::remove. Then you loop over that so you probably have a O(n^3) algorithm. You instead could use std::remove_if, which is O(n), to move all the to-be-erased elements to the end of the vector where they can be cheaply erased.:
AllPoss.erase(std::remove_if(AllPos.begin(), AllPos.end(), [&](const std::string& token, const std::string& guess) { return calculateBullAndPgia(token, guess) != answer; }), AllPos.end());

C++, return duplicate instances from an array to a string

Background to this: This is not homework, it's completely optional review for a basic c++ class. As I want to pass, I'm going through each example the best I can, This one I'm super stuck on, and have been for about three hours now.
Problem: Write a function to return a string composed of the most frequent lowercase letter found in each row of a 10 x 10 array of lowercase alphabetic chars in the range a through z.
If there is more than one most frequent character, use the one that come first alphabetically.
Use neither cin nor cout.
#include <iostream>
#include <string>
using namespace std;
string mostFrequent(char c[10][10]){
// this is the function I need to create
}
int main(){
char c[10][10] = {
'a','b','f','d','e','f','g','h','i','j',
'a','b','c','r','c','r','g','h','r','j',
'a','b','c','d','e','f','g','h','o','o',
'z','w','p','d','e','f','g','h','i','j',
'o','d','o','d','o','b','o','d','o','d',
'a','l','l','d','e','f','f','h','l','j',
'a','b','c','d','i','f','g','h','i','j',
'a','b','z','v','z','v','g','g','v','z',
'a','b','c','d','e','f','g','h','i','e',
'a','b','s','d','e','f','g','h','s','j',
};
cout << mostFrequent(c) << endl;
return 0;
}
So in research for this I found some material that allows me to count how many times a specific int or char would appear inside the array, but it doesn't quite suit the needs of the problem as it needs to return a string composed of the most frequent character. See below.
int myints[] = {10,20,30,30,20,10,10,20};
int mycount = std::count (myints, myints+8, 10);
Because it doesn't work though, I was thinking a for loop, to go row to row, I'll mostly likely need to save things into an array to count, but I'm not sure at all how to implement something like that. I even considered a caesar shift with an array, but I'm not sure where to go if that is the solution.
If I understood the task correctly, you have a matrix 10x10 and you have to create a string of length 10, where character at position i is the one that is most frequent among characters in the row i.
string mostFrequent(char c[10][10]) {
// The idea here is to find the most common character in each row and then append that character to the string
string s = "";
for (int i = 0; i < 10; i++) s += findMostFrequentCharacter(c[i]);
return s;
}
Now we just have to implement a function char findMostFrequentCharacter(char c). We are going to do that by counting all of the characters and picking the one that is most frequent (or it comes alphabetically before if there is more than one most frequent character):
char findMostFrequentCharacter(char c[10]) {
int counts[256]; // Assuming these are ASCII characters, we can have max 256 different values
// Fill it with zeroes (you can use memset to do that, but for clarity I'll write a for-loop
for (int i = 0; i < 256; i++) c[i] = 0;
// Do the actual counting
for (int i = 0; i < 10; i++) // For each character
counts[ c[i] ]++; // Increase it's count by 1, note that c[i] is going to have values between 65 (upper case A) and 122 (lower case z)
char mostFrequent = 0;
// Find the one that is most frequent
for (char ch = 'A'; ch <= 'z' ch++) // This will ensure that we iterate over all upper and lower case letters (+ some more but we don't care about it)
if (counts[ch] > counts[c]) c = ch; // Take the one that is more frequent, note that in case they have the same count nothing will happen which is what we want since we are iterating through characters in alphabetical order
return c;
}
I have written the code out of my head so I'm sorry if there are any compile errors.

Loop changing a string keep failing?

cin >> n;
string disks;
for(i=0; i < n; i++){
disks[2*i] = 1;
disks[2*i+1] = 0;
}
This keeps saying: string subscript out of range. Even if I change it to (n-1). I am trying to think of a very simple way to just set this to alternating 1 and 0s and I cant find it!
Why is this loop causing an error?
When a std::string is default-constructed it's empty; you can't just start writing to it as the underlying storage hasn't been allocated.
Instead, use string disks(n * 2, '0'); to initialise the string with space for 2 * n characters. It will be pre-filled with '0' (the zeroes), then all you have to do is go through and fill in the ones.
cin >> n;
string disks(n * 2, '0');
for (int i = 0; i < n; i++)
disks[2 * i] = '1';
Also note that you need to use '0' and '1' to get the actual character values.
When you define a string that has no initial value you cannot access it, in your example with operator[]. So, the lines:
disks[2*i] = 1;
disks[2*i+1] = 0;
are causing the error, because you are trying to access an index that doesn't exist.
If you want to assign a value to a string use concatenation:
disks += "0" + "1";
or push_back(), append(). The sequence of the assigned values will determine which will be at even and odd index.