Format any number in Indian currency style using C language - c

Indian Currency format is 12345 → "12,345" (for odd length) and 123456 → "1,23,456" (for even length). I have included all possibilities such as
1. Minus sign: "-12,345".
2. Decimal Point: "-12,345.345" or "12,345.123".
3. Zero Condition 000000.123 → "0.123".
4.Minus and Zero Condition '-000000.123' -> "-0.123"
int currencyFormatter(char av_currency[], int av_strLen, char *ap_formattedNumber)
{
char flag = 'N'; //Taking a Flag to know whether thier is a decimal Point in Currency or not
int lengthOf = 0, index = 0, i = 0, j = 0;
char *decAr = NULL;
char *tmpCurrency = NULL;//Taking two Pointers one for Array with Commas(tmpCurrency) and decAr pointer for decimal Point array
char *s = NULL;
s = strstr(av_currency, ".");//Checking for decimal Point in array
if (s > 0)
{
flag = 'D'; // Changing Flag to show Decimal Point is Present in Array
s = strchr(av_currency, '.');
index = s - av_currency; //Index at which Decimal Point is present
av_strLen = strlen(av_currency) - index; // calculated formula to know length of an array needed to contain decimal point and Numbers after that
decAr = (char*)malloc(av_strLen*sizeof(char*));//allocated Memory using malloc
decAr[av_strLen] = '\0';
memmove(decAr, &av_currency[index], av_strLen); //memmove from decimal till end of array.
av_currency[index] = '\0';
if (!decAr)//Handled Null Condition for Pointer
{
return -1;//All errors for Negative Number
}
}
lengthOf = strlen(av_currency) + (strlen(av_currency) / 2); // Derived Formula(It Works for Indian Currency Format) to know the length of an array is needed to contain numbers and Commas Together.
tmpCurrency = (char*)malloc(lengthOf*sizeof(char*));
strrev(av_currency); //Reversed Array as commas comes at multiple of 3. eg=12345 reverse=54321 wdComma=543,21 index is 3 if number would had been bigger commas would had come at 3,6.
while (av_currency[i] != '\0')
{
if (j % 3 == 0 && j >= 3 && av_currency[i] != '-')//all Commas come at multiple of 3 when you reverse an amount
{
tmpCurrency[j] = ',';//If an , is found Increment only J as
is used as index number to store in tmpcurrency
j++;
continue;
}
tmpCurrency[j] = av_currency[i];//storing the Value in tmpCurrency
i++;//Incrementing
j++;//Incrementing
}
tmpCurrency[j] = '\0';//Null Condition
if (!tmpCurrency) // Checking for NULL Pointer
{
return -2; //all errors for Negative value
}
flag == 'D' ? strcpy(av_currency, (strcat(strrev(tmpCurrency), decAr))) : strcpy(av_currency, (strrev(tmpCurrency)));//Ternary Operator
strcpy(ap_formattedNumber,av_currency);//Copying formated number into original array
free(tmpCurrency);//Releasing the memory
free(decAr);//Releasing the Memory
return 0;
}

I have solution for above question.
Please try this code.
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <stdlib.h>
char *printComma(double input_number,char *demo,char ap_it[],char ap_type[])
{
char *result = NULL;
char *lp_decimal_number = NULL;
char *main_number = NULL;
char *decimal_pos = NULL;
char zero[1] = {0};
int i = 0;
int j = 0;
int z = 0;
int cnt = 0;
int decimal_index = 0;
int lp_decimal_numberLen = 0 ;
int flag_dec = 0;
int flag_minus = 0 ;
int length_main;
int k = 0;
int length_demo=0;
sprintf(demo,"%lf",input_number);
if(strcmp(ap_type,"P") == 0)
{
if(strcmp(ap_it,"A") == 0 || strcmp(ap_it,"B") == 0)
{
sprintf_s(demo,40,"%0.4lf",input_number);
}
else
{
sprintf_s(demo,40,"%0.2lf",input_number);
}
}
else
{
sprintf_s(demo,40,"%.0lf",input_number);
}
length_demo = strlen(demo); // finds the length of original string
result = (char *)malloc((length_demo+10)*sizeof(char));
main_number = (char *)malloc((length_demo+50)*sizeof(char));
z = strspn(demo[0] == '-' ? (demo + 1) : demo , "0");
if(z != 0)
{
if(demo[0] != '-')
{
memcpy(main_number,&demo[z],length_demo);
main_number[length_demo]='\0';
}
else
{
puts(main_number);
main_number[length_demo]='\0';
flag_minus=1;
}
}
else
{
memcpy(main_number,&demo[0],length_demo);
main_number[length_demo]='\0';
}
length_main=strlen(main_number);
decimal_pos = strstr(main_number,".");
if(decimal_pos > 0)
{
decimal_index = decimal_pos - main_number ; // Getting postion of decimal
lp_decimal_numberLen = length_main - decimal_index; // Calculating the endpoint for decimal number
if(length_main > 3) //Copying the decimal part to a separate array
{
lp_decimal_number = (char *) malloc(lp_decimal_numberLen+1);
memcpy( lp_decimal_number, &main_number[decimal_index], lp_decimal_numberLen );
lp_decimal_number[lp_decimal_numberLen] = '\0';
flag_dec=1;
main_number[decimal_index]='\0';
}
}
//logic for comma starts here
strrev(main_number);
i = 0;
while(main_number[i] != '\0')
{
if (j%3 == 0 && j>=3 && main_number[i]!='-' && main_number[i]!='$')
{
result[j] = ',';
cnt++;
j++;
continue;
}
else if(cnt==1 || cnt==2)
{
result[j] = main_number[i];
}
else
{
result[j] = main_number[i];
}
i++;
j++;
}
result[j] = '\0';
if(flag_dec==0)
{
if(flag_minus==0)
return(strrev(result));
else
{
strcat(result,"-");
return(strrev(result));
}
}
else
{
if(flag_minus==0)
return(strcat(strrev(result),lp_decimal_number));
else
{
strcat(result,"-");
return(strcat(strrev(result),lp_decimal_number));
}
}
}
int main()
{
double number;
char num[25] = {0};
char it_type[] = "A";
char ap_type[] = "P";
char *formattedNumber = NULL;
printf("\n Enter the number n: ");
scanf("%lf",&number);
formattedNumber=printComma(number,num,it_type,ap_type);
printf("\n Final Result = %s ",formattedNumber);
getch();
return 0;
}

Do only positive values with your function!
Check if the value is negative before calling the function; call the function with the positive value; if it was negative to start with, add the minus sign afterwards.
int needssign = 0;
if (val < 0) needssign = 1;
indianformat(res, abs(val));
if (needssign) sprintf(res, "-%s", res);
Or make your current function a helper function and use the code above for the new improved function for formatting in Indian format.

Related

What's the most efficient way to keep track of n largest values?

I have a program that receives in input a large number of values and has to keep track of the n largest received. For example, let's say n is 3 and the input is 1,6,3,5,2 the output would have to be 6,5,3 (not necessarily in this order).
At the moment I'm using a min heap implemented via an array, but that isn't quite cutting it time-wise. Are there any alternatives I can look into?
The "(not necessarily in this order)" implies that you can have a sorted numerically output. As you only have to track values greater or equal than n, with a very large input of integer values, a wise way would be then to keep track of integer ranges instead of values.
It will heavily depend of the inputs. For hughes word integer inputs with a discrete uniform distribution, it would cost less memory and would be faster.
A simple pseudo code implementation would require for each input value to check it against a min heap ordered stack of ranges :
Range is
min as integer
max as integer
next as Range
duplicates as stack of integer
Range(pMin, pMax, pNext)
self.min = pMin
self.max = pMax
self.next = pNext
self.duplicates = empty stack of integer
Range heap_top = NULL
Range current_range = NULL
Range previous_range = NULL
boolean merge_flag
integer value
While read value from input
if value >= n Then
current_range = heap_top
previous_range = NULL
merge_flag = false
While current_range is not null
If value is current_range.min - 1 Then
current_range.min = value
merge_flag = true
Break
End If
If value is current_range.max + 1 Then
current_range.max = value
merge_flag = true
Break
End If
If value < current_range.min Then
current_range = NULL
Break
End If
If value is between current_range.min and current_range.max Then
# Here we track duplicates value
current_range.duplicates.push value
Break
End If
previous_range = current_range
current_range = current_range->next
End While
If current_range is not NULL Then
If merge_flag is true Then
If previous_range is not NULL and current_range.min - 1 is previous_range.max Then
# merge current range into previous one
previous_range.max = current_range.max
# Here we track duplicates value
previous_range.duplicates.pushall current_range.duplicates
previous_range.next = current_range.next
drop current_range
# If we need to keep a track of the range where belong the value
# current_range = previous_range
Else
If current_range.next is not NULL and current_range.max + 1 is
current_range.next.min Then
# merge next range into current one
# We use previous_range to point the next range
previous_range = current_range.next
current_range.max = previous_range.max
# Here we track duplicates value
current_range.duplicates.pushall previous_range.duplicates
current_range.next = previous_range.next
drop previous_range
End If
End If
End If
Else
If previous_range is NULL Then
current_range = new Range(value, value, heap_top)
heap_top = current_range
Else
current_range = new Range(value, value, previous_range.next)
previous_range.next = current_range
End If
End If
End If
End While
Less nodes implies less node traversal processing on the long run if the input is uniformly distributed. Less node traversal processing for each input value to process means a faster global processing, as we have then an algorithm approaching O(N) instead of O(N!) with N as the number of input values.
An example of C implementation of the the previous algorithm :
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
struct s_range {
unsigned int min;
unsigned int max;
struct s_range *next;
unsigned int *duplicates;
unsigned int duplicates_count;
};
struct s_range *new_range(unsigned int pMin,unsigned int pMax, struct s_range *pNext) {
struct s_range *lRange = malloc(sizeof(struct s_range));
if (lRange == NULL) {
perror("new_range: Failed to allocate");
return NULL;
}
lRange->min = pMin;
lRange->max = pMax;
lRange->next = pNext;
lRange->duplicates = NULL;
lRange->duplicates_count = 0;
return lRange;
}
void drop_range(struct s_range *pRange) {
if (pRange != NULL) {
if (pRange->duplicates != NULL) {
free(pRange->duplicates);
}
free(pRange);
}
}
void drop_allranges(struct s_range *pTopRange) {
struct s_range *lRange;
while (pTopRange != NULL) {
lRange = pTopRange->next;
drop_range(pTopRange);
pTopRange = lRange;
}
}
int push_duplicates(struct s_range *pRange, unsigned int pValue) {
unsigned int *lDuplicates;
if (pRange == NULL) {
return 2;
}
if (pRange->duplicates == NULL) {
lDuplicates = malloc(sizeof(unsigned int));
} else {
lDuplicates = realloc(pRange->duplicates, (pRange->duplicates_count + 1) * sizeof(unsigned int));
}
if (lDuplicates == NULL) {
perror("push_duplicates: failed to allocate...");
return 1;
}
lDuplicates[pRange->duplicates_count++] = pValue;
pRange->duplicates = lDuplicates;
return 0;
}
int pushall_duplicates(struct s_range *pRangeDst, struct s_range *pRangeSrc) {
unsigned int *lDuplicates;
if (pRangeDst == NULL || pRangeSrc == NULL) {
return 2;
}
if (pRangeSrc->duplicates == NULL) {
return 0;
}
if (pRangeDst->duplicates == NULL) {
lDuplicates = malloc(pRangeSrc->duplicates_count * sizeof(unsigned int));
} else {
lDuplicates = realloc(pRangeDst->duplicates, (pRangeDst->duplicates_count + pRangeSrc->duplicates_count) * sizeof(unsigned int));
}
if (lDuplicates == NULL) {
perror("pushall_duplicates: failed to allocate...");
return 1;
}
memcpy(&lDuplicates[pRangeDst->duplicates_count], pRangeSrc->duplicates, pRangeSrc->duplicates_count * sizeof(unsigned int));
pRangeDst->duplicates_count += pRangeSrc->duplicates_count;
pRangeDst->duplicates = lDuplicates;
return 0;
}
int main(int nbargs, char *argv[]) {
struct s_range *lHeapTop = NULL;
struct s_range *lCurrentRange;
struct s_range *lPreviousRange;
unsigned int lMergeFlag;
unsigned int lValue;
unsigned int lN = 3;
unsigned int lDispFlag = 0;
if (nbargs > 1) {
lN = atoi(argv[1]);
}
if (nbargs > 2) {
lDispFlag = atoi(argv[2]);
}
while(fread(&lValue, sizeof(unsigned int), 1, stdin) > 0) {
if (lValue >= lN) {
lCurrentRange = lHeapTop;
lPreviousRange = NULL;
lMergeFlag = 0;
while(lCurrentRange != NULL) {
if (lCurrentRange->min - 1 == lValue) {
lCurrentRange->min = lValue;
lMergeFlag = 1;
break;
}
if (lCurrentRange->max + 1 == lValue) {
lCurrentRange->max = lValue;
lMergeFlag = 1;
break;
}
if (lValue < lCurrentRange->min) {
lCurrentRange = NULL;
break;
}
if (lValue >= lCurrentRange->min && lValue <= lCurrentRange->max) {
if (push_duplicates(lCurrentRange, lValue) != 0) {
drop_allranges(lHeapTop);
return 1;
}
break;
}
lPreviousRange = lCurrentRange;
lCurrentRange = lCurrentRange->next;
}
if (lCurrentRange != NULL) {
if (lMergeFlag == 1) {
if (lPreviousRange != NULL && lCurrentRange->min - 1 == lPreviousRange->max) {
lPreviousRange->max = lCurrentRange->max;
if (pushall_duplicates(lPreviousRange, lCurrentRange) != 0) {
drop_allranges(lHeapTop);
return 1;
}
lPreviousRange->next = lCurrentRange->next;
drop_range(lCurrentRange);
} else {
if (lCurrentRange->next != NULL && lCurrentRange->max + 1 == lCurrentRange->next->min) {
lPreviousRange = lCurrentRange->next;
lCurrentRange->max = lPreviousRange->max;
if (pushall_duplicates(lCurrentRange, lPreviousRange) != 0) {
drop_allranges(lHeapTop);
return 1;
}
lCurrentRange->next = lPreviousRange->next;
drop_range(lPreviousRange);
}
}
}
} else {
if (lPreviousRange == NULL) {
lCurrentRange = new_range(lValue, lValue, lHeapTop);
if (lCurrentRange == NULL) {
drop_allranges(lHeapTop);
return 1;
}
lHeapTop = lCurrentRange;
} else {
lCurrentRange = new_range(lValue, lValue, lPreviousRange->next);
if (lCurrentRange == NULL) {
drop_allranges(lHeapTop);
return 1;
}
lPreviousRange->next = lCurrentRange;
}
}
}
}
// Check the results
if (lDispFlag == 1) {
lCurrentRange = lHeapTop;
while(lCurrentRange != NULL) {
printf("From %u to %u dup:", lCurrentRange->min, lCurrentRange->max);
for (unsigned int lInd = 0; lInd < lCurrentRange->duplicates_count; lInd++) {
printf(" %u", lCurrentRange->duplicates[lInd]);
}
printf("\n");
lCurrentRange = lCurrentRange->next;
}
}
// Cleaning
drop_allranges(lHeapTop);
return 0;
}
With a discrete uniform distribution set of 65 536 words, on a x64 Debian Buster (4670K CPU), this code (range executable) is three times faster than a classic min heap one (node executable):
bash:~$ awk 'BEGIN { for (idx=0;idx<65536;idx++) { v=rand()*256; v2=rand()*256; printf("%c%c%c%c",v,v2,0,0); }}' > data.bin
bash:~$ time cat data.bin | ./range 3
real 0m5.629s
user 0m5.516s
sys 0m0.031s
bash:~$ time cat data.bin | ./node 3
real 0m15.618s
user 0m15.328s
sys 0m0.016s

Converting value from a string into an int

I have read this question ( Convert a string into an int ) before posting but I still have doubts.
I am very new to C and I'am trying to write a function which takes a string as parameter , something like this :
"99Hello" or "123ab4c"
And then returns the first the numbers it found into an int. So the result would be :
99 or 123
I'am trying to do this by finding the characters in the string(which correspond to numbers in the ASCII table) and then store them in the int I have created and returned by the function.
I'am having trouble though because when I find those character ( which correspond to numbers) I don't know how to save them to an int data type variable or how to convert them. I know there is a function called atoi which does this automatically but I would like to know how to do this by myself.
This is what I wrote so far :
int ReturnInt(char *str)
{
int i;
int new;
i = 0;
new = 0;
while (str[i] != '\0')
{
if( str[i] >= '0' && str[i] <= '9')
{
str[i] = new - '0';
}
i++;
}
return (new);
}
I think you should be able to form the desired integer from digits by multiplying them by 10 and adding them while iterating. Moreover, I think your loop's terminating condition should also include isDigit check
For example, for input 99Hello
i = 0, new = 0 -> new = 0 * 10 + 9 (9)
i = 1, new = 9 -> new = 9 * 10 + 9 (99)
i = 2, condition not satisfied as it's not a digit
int ReturnInt(char str[]) {
int i;
int new;
i = 0;
new = 0;
while (str[i] != '\0' && (str[i] >= '0' && str[i] <= '9'))
{
int currentDigit = str[i] - '0';
new = new * 10 + currentDigit;
i++;
}
return (new);
}
You just have to take a place holder , and that has to be multiplied by 10 for every iteration so that we get 10, 100, 1000 place holders and we can add that quantity to remaining numbers.
#include <stdio.h>
#include <ctype.h>
int str2num(char*strnum);
int main()
{
char *num1 = "122AB";
char *num2 = "2345AB9C";
char *num3 = "A23AB9C";
printf("num1 = %d\n", str2num(num1));
putchar('\n');
printf("num2 = %d\n", str2num(num2));
putchar('\n');
printf("num3 = %d\n", str2num(num3));
return 0;
}
int str2num(char*strnum)
{
int num = 0;
int ph = 10;// for getting tens,100s etc
while(strnum && *strnum && isdigit(*strnum))
{
num = num * ph + ( (*strnum) - '0');
strnum++;
}
return num;
}

How do I check the first two characters of my char array in C?

This is code to create a similar C library function atoi() without the use of any C runtime library routines.
I'm currently stuck on how to check for the first two digits of the char array s to see whether the input begins with "0x".
If it starts with 0x, this means that I can then convert it in to hexadecimal.
#include <stdio.h>
int checkforint(char x){
if (x>='0' && x<='9'){
return 1;
}
else{
return 0;
}
}
unsigned char converthex(char x){
//lets convert the character to lowercase, in the event its in uppercase
x = tolower(x);
if (x >= '0' && x<= '9') {
return ( x -'0');
}
if (x>='a' && x<='f'){
return (x - 'a' +10);
}
return 16;
}
int checkforhex(const char *a, const char *b){
if(a = '0' && b = 'x'){
return 1;
}else{
return 0;
}
}
//int checkforint
/* We read an ASCII character s and return the integer it represents*/
int atoi_ex(const char*s, int ishex)
{
int result = 0; //this is the result
int sign = 1; //this variable is to help us deal with negative numbers
//we initialise the sign as 1, as we will assume the input is positive, and change the sign accordingly if not
int i = 0; //iterative variable for the loop
int j = 2;
//we check if the input is a negative number
if (s[0] == '-') { //if the first digit is a negative symbol
sign = -1; //we set the sign as negative
i++; //also increment i, so that we can skip past the sign when we start the for loop
}
//now we can check whether the first characters start with 0x
if (ishex==1){
for (j=2; s[j]!='\0'; ++j)
result = result + converthex(s[j]);
return sign*result;
}
//iterate through all the characters
//we start from the first character of the input and then iterate through the whole input string
//for every iteration, we update the result accordingly
for (; s[i]!='\0'; ++i){
//this checks whether the current character is an integer or not
//if it is not an integer, we skip past it and go to the top of the loop and move to the next character
if (checkforint(s[i]) == 0){
continue;
} else {
result = result * 10 + s[i] -'0';
}
//result = s[i];
}
return sign * result;
}
int main(int argc)
{
int isithex;
char s[] = "-1";
char a = s[1];
char b = s[2];
isithex=checkforhex(a,b);
int val = atoi_ex(s,isithex);
printf("%d\n", val);
return 0;
}
There are several errors in your code. First, in C you start counting from zero. So in main(), you should write:
char a = s[0];
char b = s[1];
isithex = checkforhex(a, b);
Then, in checkforhex(), you should use == (two equal signs) to do comparisons, not =. So:
if (a == '0' && b == 'x')
However, as pointed out by kaylum, why not write the function to pass a pointer to the string instead of two characters? Like so:
int checkforhex(const char *str) {
if (str[0] == '0' && str[1] == 'x') {
...
}
}
And in main() call it like so:
isithex = checkforhex(s);

A Function that will convert number bases and Errors for illegal inputs

I have written a function that will convert strings between different user specified number bases. For example octal is 8, decimal is 10. Letters A to Z could be considered up to base 26.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<math.h>
#define MAXBUF 64
int baseconv(char s[], int sb, char d[], int db);
void main()
{
char s[MAXBUF+1], d[MAXBUF+1]; // source, destination value (as char string)
int sb,db; // source, destination base
int decval; // calculated decimal value
char buf[MAXBUF+10]; // temp buffer
char *p; // pointer to string
printf("Enter src value, src base, dst base: ");
gets(buf);
p=strtok(buf," ,");
while(stricmp(p,"END"))
{
strcpy(s,p);
p=strtok(NULL," ,"); // or sb=atoi(strtok(NULL," ,"))
sb=atoi(p);
p=strtok(NULL," ,"); // or db=atoi(strtok(NULL," ,"))
db=atoi(p);
decval = baseconv(s,sb,d,db);
printf("%s|%d = %d|10 = %s|%d\n", s,sb,decval,d,db);
printf("Enter src value, src base, dst base: ");
gets(buf);
p=strtok(buf," , ");
}
}
// actual baseconv() function
int baseconv(char s[], int sb, char d[], int db)
{
char t1[MAXBUF+10];
char t[MAXBUF+10];
int v=0,i=0,j=0,temp,k=0;
while(s[i])
{
if(s[i]>=48 && s[i] < 58)
v = v * sb + (s[i]-48);
else if(s[i]>=65 && s[i]<71)
v = v * sb + (s[i]-65)+10;
else if(s[i]>=97 && s[i]<103)
v = v * sb + (s[i]-97)+10;
i++;
}
temp=v;
while(v)
{
if(v%db+48 >= 48 && v%db+48 < 58)
t[j] =(v%db)+48;
else if(v%db+55 >=65)
t[j] =(v%db)+55;
else if(v%db+87 >=97)
t[j] =(v%db)+87;
v = v/db;
j++;
}
for(int n=j-1;n>=0;n--)
{
t1[k]=t[n];
k++;
}
t1[j]='\0';
strcpy(d,t1);
return temp;
}
Output is like this-
Enter source value, source base, dest base: 1234, 8, 16
1234|8 = 668|10 = 29C|16"
And
Enter source value, source base, dest base: face, 16, 8
face|16 = 64206|10 = 175316|8"
However, I cannot get it to specify if the source value is illegal for the specified source base (for example 1234|3, return -1, and place the value "ERROR" in d[].
Output WOULD be like this-
Enter source value, source base, dest base: 12345, 5, 10
12345|5 = -1|10 = ERROR|10"
How would I implement the return -1 and ERROR?
You can write a function that maps a character to its ordinal value for a given base.
int map_digit_to_ordinal (int x) {
static int map[MAX_CHAR];
const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz";
const char *p;
if (x < 0 || x >= MAX_CAR) return -1;
if (map['1'] == 0) {
for (p = digits; *p; ++p) {
map[*p] = 1 + p - digits;
map[toupper(*p)] = 1 + p - digits;
}
}
return map[x] - 1;
}
You can have a different function to check if the digit falls within your desired base.
int digit_in_base (int digit, int base) {
if (base > 36) return -1;
if (digit < base) return digit;
return -1;
}
Then, your conversion function can use this function to map the potential digit to the right value. If the returned value is -1, your function should return early, writing "ERROR" to the destination.
Now, your conversion function loop can make the appropriate checks.
while(s[i]) {
temp = map_digit_to_ordinal(s[i]);
temp = digit_in_base(temp, sb);
if (temp == -1) {
strcpy(d, "ERROR");
return -1;
}
v = v * sb + temp;
i++;
}
/* rest of function ... */

Searching a particular word in a matrix of characters

I was trying to search for a particular word in a matrix of characters through C but was unable to come to a fixed solution.
For ex:
Suppose I have to search for the word INTELLIGENT in a matrix of characters (3*9)
(Once you have picked a character from the matrix to form a sentence, you cannot pick it again to form the same sentence.There is a path from any cell to all its neighboring cells. A neighbor may share an edge or a corner.)
IIIINN.LI
....TTEGL
.....NELI
Output: YES (the word INTELLIGENT can be found)
Can anybody please give a solution to the above problem !!!!
Use a depth first search.
You can do this using a recursive algorthm. Find all the (unused) places containing the first letter then see if it is possible to find the rest of the word on the remaining board by starting from one of the adjacent squares.
#include <stdio.h>
char Matrix[3][9] = {
{ 'I','I','I','I','N','N','.','L','I'},
{ '.','.','.','.','T','T','E','G','L'},
{ '.','.','.','.',',','N','E','L','I'}
};
char Choice[3][9] = { { 0 }, { 0 }, { 0 } };
const char WORD[] = "INTELLIGENT";
const int Len = sizeof(WORD)-1;
int Path[sizeof(WORD)-1] = { 0 };
char get(int row, int col){
if(1 > col || col > 9) return '\0';
if(1 > row || row > 3) return '\0';
if(Choice[row-1][col-1] || Matrix[row-1][col-1] == '.')
return '\0';
else
return Matrix[row-1][col-1];
}
#define toLoc(r, c) (r)*10+(c)
#define getRow(L) L/10
#define getCol(L) L%10
int search(int loc, int level){
int r,c,x,y;
char ch;
if(level == Len) return 1;//find it
r = getRow(loc);
c = getCol(loc);
ch = get(r,c);
if(ch == 0 || ch != WORD[level]) return 0;
Path[level]=toLoc(r,c);
Choice[r-1][c-1] = 'v';//marking
for(x=-1;x<=1;++x){
for(y=-1;y<=1;++y){
if(search(toLoc(r+y,c+x), level + 1)) return 1;
}
}
Choice[r-1][c-1] = '\0';//reset
return 0;
}
int main(void){
int r,c,i;
for(r=1;r<=3;++r){
for(c=1;c<=9;++c){
if(search(toLoc(r,c), 0)){
printf("YES\nPath:");
for(i=0;i<Len;++i){
printf("(%d,%d)", getRow(Path[i]), getCol(Path[i]));
}
printf("\n");
return 0;
}
}
}
printf("NO\n");
return 0;
}
I think this is what you mean..... Though it seems simpler to what you currently have been offered, so I may have misunderstood the question.
I use Numpy to reshape an arbitrary array into a single
list of letters, then we create a mask of the search term and
a copy of the input list.
I tick off each letter to search for while updating the mask.
import numpy as np
import copy
def findInArray(I,Word):
M=[list(x) for x in I]
M=list(np.ravel(M))
print "Letters to start: %s"%"".join(M)
Mask=[False]*len(Word)
T = copy.copy(M)
for n,v in enumerate(Word):
try:
p=T.index(v)
except ValueError:
pass
else:
T[p]=''
Mask[n]=True
print "Letters left over: %s"%"".join(T)
if all(Mask):print "Found %s"%Word
else:print "%s not Found"%Word
print "\n"
return all(Mask)
I=["IIIINN.LI","....TTEGL",".....NELI"]
findInArray(I,"INTEL")
findInArray(I,"INTELLIGENT")
findInArray(I,"INTELLIGENCE")
Example output
Letters to start: IIIINN.LI....TTEGL.....NELI
Letters left over: IIIN.I....TGL.....NELI
Found INTEL
Letters to start: IIIINN.LI....TTEGL.....NELI
Letters left over: II.I.........NLI
Found INTELLIGENT
Letters to start: IIIINN.LI....TTEGL.....NELI
Letters left over: II.I....T.....NLI
INTELLIGENCE not Found
#include <stdio.h>
#define ROW 1
#define COL 11
char Matrix[ROW][COL] = { { 'I','N','T','E','L','L','I','G','E', 'N', 'T'} };
char Choice[ROW][COL] = { { 0 } };
const char WORD[] = "INTELLIGENT";
const int Len = sizeof(WORD)-1;
int Path[sizeof(WORD)-1] = { 0 };
char get(int row, int col){
if(1 > col || col > COL) return '\0';
if(1 > row || row > ROW) return '\0';
if(Choice[row-1][col-1] || Matrix[row-1][col-1] == '.')
return '\0';
else
return Matrix[row-1][col-1];
}
#define toLoc(r, c) (r)*16+(c)
#define getRow(L) L/16
#define getCol(L) L%16
int search(int loc, int level){
int r,c,x,y;
char ch;
if(level == Len) return 1;//find it
r = getRow(loc);
c = getCol(loc);
ch = get(r,c);
if(ch == 0 || ch != WORD[level]) return 0;
Path[level]=toLoc(r,c);
Choice[r-1][c-1] = 'v';//marking
for(x=-1;x<=1;++x){
for(y=-1;y<=1;++y){
if(search(toLoc(r+y,c+x), level + 1)) return 1;
}
}
Choice[r-1][c-1] = '\0';//reset
return 0;
}
int main(void){
int r,c,i;
for(r=1;r<=ROW;++r){
for(c=1;c<=COL;++c){
if(search(toLoc(r,c), 0)){
printf("YES\nPath:");
for(i=0;i<Len;++i){
printf("(%d,%d)", getRow(Path[i]), getCol(Path[i]));
}
printf("\n");
return 0;
}
}
}
printf("NO\n");
return 0;
}

Resources