user5844653
user5844653

Reputation: 45

how do I correct this code to check for anagrams?

#include <stdio.h>

main()
{
    char *a = "stack";
    char *b = "cats";
    int l = 0;  // for length of string b 
    clrscr();
    while (*b != NULL) 
        {
            l++;
            b++;
        }
    b--; // now b points to last char of the string 
    // printf("%d\n", l);
    while ((*a - *b == 32) || (*a == *b))
        {
            printf("%c %c\n", *a, *b);
            a++;
            b--;
            l--;
            if (l == 0)
                break;
        }
    l == 0 ? printf("anagrams") : printf("not anagrams");
    getch();
}

I wrote the code to check whether two strings a and b are anagrams.

the code displays a false positive when b is shorter in length than a and is a substring of a.

for eg. b is "cats" which in reverse is "stac" and a is "stack" the code shows a and b as anagrams

Upvotes: 0

Views: 253

Answers (3)

David C. Rankin
David C. Rankin

Reputation: 84531

Continuing from my comment, you can use a simple frequency array (recording how many times each character of the subject appears) and do the same thing for the proposed anagram and then simply compare the two frequency arrays to determine if the proposed anagram is in fact an anagram of the subject.

For example, you could do something similar to the following:

#include <stdio.h>
#include <string.h>

#define MAXF 62

int main (int argc, char **argv) {

    char *sub = argc > 1 ? argv[1] : "anagram",
         *ana = argc > 2 ? argv[2] : "nag a ram",
         *sp = sub, *ap = ana;

    int subf[MAXF] = {0},   /* subject frequency array */
        anaf[MAXF] = {0};   /* anagram frequency array */

    while (*sp) {   /* fill subject frequency array */
        if ('a' <= *sp && *sp <= 'z')
            subf[*sp - 'a']++;
        else if ('A' <= *sp && *sp <= 'Z')
            subf[*sp - 'A' + 26]++;
        else if ('0' <= *sp && *sp <= '9')
            subf[*sp - '0' + 52]++;
        sp++;
    }

    while (*ap) {   /* fill anagram frequency array */
        if ('a' <= *ap && *ap <= 'z')
            anaf[*ap - 'a']++;
        else if ('A' <= *ap && *ap <= 'Z')
            anaf[*ap - 'A' + 26]++;
        else if ('0' <= *ap && *ap <= '9')
            anaf[*ap - '0' + 52]++;
        ap++;
    }

    /* if character frequency arrays are equal - it's an anagram */
    if (memcmp (subf, anaf, MAXF * sizeof *subf) == 0)
        printf ("'%s' is an anagram of '%s'\n", ana, sub);
    else
        printf ("'%s' is NOT an anagram of '%s'\n", ana, sub);

    return 0;
}

Example Use/Output

Checking the default values of anagram and nag a ram

$ ./bin/anagram
'nag a ram' is an anagram of 'anagram'

Checking if nag a rim is an anagram of the subject word anagram

$ ./bin/anagram anagram "nag a rim"
'nag a rim' is NOT an anagram of 'anagram'

Upvotes: 0

rationalcoder
rationalcoder

Reputation: 1687

First, the code you are writing looks more like you trying to check for the two words being palindromic. If that was your intent, you are taking the length of the smaller string, making l hit 0 before the last character of a is seen.

If you didn't want to check for palindromes, I would imagine that you are really looking for the code for checking if a is a permutation of b, since that code is the same as checking for an anagram if you just have one word.

Don't do what others have suggested and sort the strings and compare. That ranges from comparable to much worse than three, simple linear traversals, albeit with a small space trade-off and a bound on number of possible char occurrences in a string.

The logic is this: make a map from chars to occurrence values indicating what chars are present in a and how many times they occurred. Then, go through b once making sure that every char is present, decrementing the occurrence count. Then, go through b again, making sure all occurrences are zero.

Here:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

// Only works for single words, but you get the idea.
int palindrome(const char* a, const char* b) {
    ssize_t len_a = (ssize_t)strlen(a);
    ssize_t len_b = (ssize_t)strlen(b);
    if (len_a != len_b) return 0;

    b += (len_b - 1);
    while (len_a--) if (*a++ != *b--) return 0;
    return 1;
}

 // Really checks for a case-sensitive permutations.
int anagram(const char* a, const char* b) {
    size_t len_a = strlen(a);
    size_t len_b = strlen(b);
    if (len_a != len_b) return 0;

    uint16_t occurrences[256] = {0};

    for (; *a; occurrences[(int)*a]++, a++);
    for (; *b; occurrences[(int)*b]--, b++) 
        if (!occurrences[(int)*b]) return 0;

    b -= len_b;
    for (; *b; b++) if (occurrences[(int)*b]) return 0;

    return 1;
}

 int main(void) {
    const char *a = "stack";
    const char *b = "kcats";
    printf("anagram: %d\n", anagram(a, b));

    b = "cats";
    printf("anagram: %d\n", anagram(a, b));

    b = "kcbts";
    printf("anagram: %d\n", anagram(a, b));

    a = "aabbcdddd";
    b = "aaddddbbc";
    printf("anagram: %d\n", anagram(a, b));

    a = "aabbcddcd";
    b = "aadddddbc";
    printf("anagram: %d\n", anagram(a, b));

    return EXIT_SUCCESS;
}

Note that when you do any of these kinds of algorithms, there is an early trivial false condition if the lengths of the strings differ.

Also, the code is case-sensitive here for simplicity, but that is easily changed.

Output:

anagram: 1
anagram: 0
anagram: 0
anagram: 1
anagram: 0

Upvotes: 1

Erik Nyquist
Erik Nyquist

Reputation: 1317

Some pseudo-code for checking if two strings are anagrams of each other (using your variable names):

if (strlen(a) != strlen(b))
    // Not an anagram
    return

char *a_sorted = sort_chars(a)
char *b_sorted = sort_chars(b)

// Once the characters in each word are re-arranged in alphabetical
// order, we can just test for equality. Anagrams will be equal
// (Note that this will not work on multi-word strings with differing
// numbers of whitespace characters)
if (strcmp(a_sorted, b_sorted) == 0)
    // Anagram!
else
    // Not an anagram

The real work here is in the sort_chars(in) function, which sorts the characters in the in string alphabetically, and returns a pointer to a new string containing the sorted characters. Using the numeric ASCII values of the characters (they're already in alphabetical order, yay someone's doing something right out there!), something like bubble sort (or any other sorting algorithm you want to use) should work just fine.

Upvotes: 1

Related Questions