patterncMajor
Brute Force Algorithm in C
Viewed 0 times
brutealgorithmforce
Problem
This is a simple brute force algorithm that I have programmed in C. All the program does is print out every possible combination of the given
I would prefer suggestions on how to improve the algorithm, or decrease run-time. Any other suggestions are acceptable though.
alphabet for the given length.I would prefer suggestions on how to improve the algorithm, or decrease run-time. Any other suggestions are acceptable though.
#include
#include
#include
static const char alphabet[] =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789";
static const int alphabetSize = sizeof(alphabet) - 1;
void bruteImpl(char* str, int index, int maxDepth)
{
for (int i = 0; i < alphabetSize; ++i)
{
str[index] = alphabet[i];
if (index == maxDepth - 1) printf("%s\n", str);
else bruteImpl(str, index + 1, maxDepth);
}
}
void bruteSequential(int maxLen)
{
char* buf = malloc(maxLen + 1);
for (int i = 1; i <= maxLen; ++i)
{
memset(buf, 0, maxLen + 1);
bruteImpl(buf, 0, i);
}
free(buf);
}
int main(void)
{
bruteSequential(3);
return 0;
}Solution
I'm going to skip reviewing the OP's code, which has already been reviewed quite nicely by others. Instead I'm just going to show a much faster version and explain it.
What is the algorithm?
Basically the way the algorithm works is that a buffer is created that holds
On every iteration, the function uses
Whenever the third to last character wraps around, then we also need to update the fourth to last letter. If that wraps around, the fifth to last letter is also updated, etc. This continues until the first letter wraps around, at which point we are done.
How fast is it?
For all testing, I outputted to
As you can see, this algorithm is very fast.
The code
Both programs are available here on GitHub. I'll show the 2 character variation below:
`static void generate(int maxlen)
{
int alphaLen = strlen(alphabet);
int len = 0;
char buffer = malloc((maxlen + 1) alphaLen * alphaLen);
int letters = malloc(maxlen sizeof(int));
if (buffer == NULL || letters == NULL) {
fprintf(stderr, "Not enough memory.\n");
exit(1);
}
// This for loop generates all 1 letter patterns, then 2 letters, etc,
// up to the given maxlen.
for (len=1;len<=maxlen;len++) {
// The stride is one larger than len because each line has a '\n'.
int i;
int stride = len+1;
int bufLen = stride alphaLen alphaLen;
if (len == 1) {
// Special case. The main algorithm hardcodes the last two
// letters, so this case needs to be handled separately.
int j = 0;
bufLen = (len + 1) * alphaLen;
for (i=0;i= alphaLen)
letters[i] = 0;
// Set this letter in the proper places in the buffer.
c = alphabet[letters[i]];
for (j=i;j
What is the algorithm?
Basically the way the algorithm works is that a buffer is created that holds
alphaLen^2 patterns, where alphaLen is the length of the alphabet. A pattern is one combination, such as "aaaaa\n". The reason that alphaLen^2 patterns are used is because the buffer is prepopulated with the last 2 letters already set to all possible combinations. So for example, the buffer initially looks like (for length 5 patterns):"aaaaa\naaaab\naaaac\n ... aaa99\n" (62*62 patterns, 23064 bytes in length)
On every iteration, the function uses
write() to output the buffer, and then increments the third to last letter. This involves writing that letter alphaLen^2 times (once per pattern). So the first iteration goes like:"aabaa\naabab\naabac\n ... aab99\n"
^ ^ ^ ^
| | | |
+------+------+-----------+----- Characters written to buffer (62*62 changes)
Whenever the third to last character wraps around, then we also need to update the fourth to last letter. If that wraps around, the fifth to last letter is also updated, etc. This continues until the first letter wraps around, at which point we are done.
How fast is it?
For all testing, I outputted to
/dev/null so that my hard drive speed would not be the limiting factor. I tried the OP's program for 5 letter patterns but for me it took way too long (203 seconds). So I'll use Edward's estimate of 18 seconds for the OP's program instead. I also tested Edward's program on my machine, as well as a second program I wrote where I extended the algorithm to hardcode the last 3 characters instead of 2. I am using Cygwin gcc (32-bit) with -O4 on a Windows desktop. Here are the results:Time (secs) Length Program
----------- ------ -------
18.0 5 syb0rg
9.6 5 Edward
0.4 5 JS1 (2 characters)
0.4 5 JS1 (3 characters)
665.0 6 Edward
26.0 6 JS1 (2 characters)
24.2 6 JS1 (3 characters)
1513.7 7 JS1 (3 characters)
As you can see, this algorithm is very fast.
The code
Both programs are available here on GitHub. I'll show the 2 character variation below:
`static void generate(int maxlen)
{
int alphaLen = strlen(alphabet);
int len = 0;
char buffer = malloc((maxlen + 1) alphaLen * alphaLen);
int letters = malloc(maxlen sizeof(int));
if (buffer == NULL || letters == NULL) {
fprintf(stderr, "Not enough memory.\n");
exit(1);
}
// This for loop generates all 1 letter patterns, then 2 letters, etc,
// up to the given maxlen.
for (len=1;len<=maxlen;len++) {
// The stride is one larger than len because each line has a '\n'.
int i;
int stride = len+1;
int bufLen = stride alphaLen alphaLen;
if (len == 1) {
// Special case. The main algorithm hardcodes the last two
// letters, so this case needs to be handled separately.
int j = 0;
bufLen = (len + 1) * alphaLen;
for (i=0;i= alphaLen)
letters[i] = 0;
// Set this letter in the proper places in the buffer.
c = alphabet[letters[i]];
for (j=i;j
Context
StackExchange Code Review Q#38474, answer score: 20
Revisions (0)
No revisions yet.