HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMajor

Brute Force Algorithm in C

Submitted by: @import:stackexchange-codereview··
0
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 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 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.