سؤال

I was preparing for my interview and started working from simple C programming questions. One question I came across was to check if a given string is palindrome. I wrote a a code to find if the user given string is palindrome using Pointers. I'd like to know if this is the effective way in terms of runtime or is there any enhancement I could do to it. Also It would be nice if anyone suggests how to remove other characters other than letters (like apostrophe comas) when using pointer.I've added my function below. It accepts a pointer to the string as parameter and returns integer.

int palindrome(char* string)
{
    char *ptr1=string;
    char *ptr2=string+strlen(string)-1;
    while(ptr2>ptr1){
        if(tolower(*ptr1)!=tolower(*ptr2)){
            return(0);
        }
        ptr1++;ptr2--;
    }
    return(1);
}
هل كانت مفيدة؟

المحلول

"how to remove other characters other than letters?"

I think you don't want to actually remove it, just skip it and you could use isalpha to do so. Also note that condition ptr2 > ptr1 will work only for strings with even amount of characters such as abba, but for strings such as abcba, the condition should be ptr2 >= ptr1:

int palindrome(char* string)
{
    size_t len = strlen(string);

    // handle empty string and string of length 1:
    if (len == 0) return 0;
    if (len == 1) return 1;

    char *ptr1 = string;
    char *ptr2 = string + len - 1;
    while(ptr2 >= ptr1) {
        if (!isalpha(*ptr2)) {
            ptr2--;
            continue;
        }
        if (!isalpha(*ptr1)) {
            ptr1++;
            continue;
        }
        if( tolower(*ptr1) != tolower(*ptr2)) {
            return 0;
        }
        ptr1++; ptr2--;
    }
    return 1;
}

you might need to #include <ctype.h>

نصائح أخرى

How about doing like this if you want to do it using pointers only:

int main()
{
 char str[100];
 char *p,*t;
 printf("Your string : ");
 gets(str);
 for(p=str ; *p!=NULL ; p++);
  for(t=str, p-- ; p>=t; )
  {
    if(*p==*t)
    {
        p--;
        t++;
    }
    else
        break;
  }
  if(t>p)
       printf("\nPalindrome");
  else
       printf("\nNot a palindrome");
  getch();
  return 0;
}
int main()
{   

const char *p = "MALAYALAM";

int count = 0;
int len = strlen(p);
for(int i = 0; i < len; i++ )
{
    if(p[i] == p[len - i - 1])
        count++;
}

cout << "Count: " << count;
if(count == len)
    cout << "Palindrome";
else
    cout << "Not Palindrome";

return 0;
}

I have actually experimented quite a lot with this kind of problem.

There are two optimisations that can be done:

  • Check for odd string length, odd stings can't be palindromes
  • Start using vectorised compares, but this only really gives you performance if you expect a lot of palindromes. If the majority of your strings aren't palindromes you are still best off with byte by byte comparisons. In fact my vectorised palindrome checker ran 5% slower then the non-vectorised just because palindromes were so rare in the input. The extra branch that decided vectorised vs non vectorised made this big difference.

Here is code draft how you can do it vectorised:

int palindrome(char* string)
{
    size_t length = strlen(string);

    if (length >= sizeof(uintptr_t)) { // if the string fits into a vector
        uintptr_t * ptr1 = (uintptr_t*)string;
        size_t length_v /= sizeof(uintptr_t);
        uintptr_t * ptr2 = (uintptr_t*)(string + (length - (length_v * sizeof(uintptr_t)))) + length_v - 1;

        while(ptr2>ptr1){
            if(*ptr1 != bswap(*ptr2)){ // byte swap for your word length, x86 has an instruction for it, needs to be defined separately
                return(0);
            }
            ptr1++;ptr2--;
        }

    } else {
        // standard byte by byte comparison
    }
    return(1);
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top