📄 anagram.c
字号:
cchPhraseLength = 0; while ((ch = *pchPhrase++) != '\0') { if (isalpha(ch)) { ch = tolower(ch); lPhrase(ch).uFrequency++; cchPhraseLength++; } } /* Build masks */ iq = 0; /* which quad being used */ cbtUsed = 0; /* bits used so far */ for (i = 0; i < ALPHABET; i++) { if (alPhrase[i].uFrequency == 0) { auGlobalFrequency[i] = ~0; /* to make it sort last */ } else { auGlobalFrequency[i] = 0; for (cbtNeed = 1, qNeed = 1; alPhrase[i].uFrequency >= qNeed; cbtNeed++, qNeed <<= 1); if (cbtUsed + cbtNeed > MASK_BITS) { if (++iq >= MAX_QUADS) Fatal("MAX_QUADS not large enough\n", 0); cbtUsed = 0; } alPhrase[i].uBits = qNeed-1; if (cbtUsed) qNeed <<= cbtUsed; aqMainSign[iq] |= qNeed; aqMainMask[iq] |= (Quad)alPhrase[i].uFrequency << cbtUsed; alPhrase[i].uShift = cbtUsed; alPhrase[i].iq = iq; cbtUsed += cbtNeed; } }}PWordNewWord(void) { PWord pw; pw = (Word *)malloc(sizeof(Word)); if (pw == NULL) Fatal("Out of memory after %d candidates\n", cpwCand); return pw;}/* wprint -- print a word, followed by a space * * We would normally just use printf, but the string being printed is * is a huge pointer (on an IBM PC), so special care must be taken. */void wprint(char * pch) { printf("%s ", pch);}PWord NextWord(void);/* NextWord -- get another candidate entry, creating if necessary */PWord NextWord(void) { PWord pw; if (cpwCand >= MAXCAND) Fatal("Too many candidates\n", 0); pw = apwCand[cpwCand++]; if (pw != NULL) return pw; apwCand[cpwCand-1] = NewWord(); return apwCand[cpwCand-1];}/* BuildWord -- build a Word structure from an ASCII word * If the word does not fit, then do nothing. */void BuildWord(char * pchWord) { unsigned char cchFrequency[ALPHABET]; int i; char * pch = pchWord; PWord pw; int cchLength = 0; bzero(cchFrequency, sizeof(unsigned char)*ALPHABET); /* Zero(cchFrequency); */ /* Build frequency table */ while ((i = *pch++) != '\0') { if (!isalpha(i)) continue; i = ch2i(tolower(i)); if (++cchFrequency[i] > alPhrase[i].uFrequency) return; ++cchLength; } Debug(wprint(pchWord);) /* Update global count */ for (i = 0; i < ALPHABET; i++) auGlobalFrequency[i] += cchFrequency[i]; /* Create a Word structure and fill it in, including building the * bitfield of frequencies. */ pw = NextWord(); bzero(pw->aqMask, sizeof(Quad)*MAX_QUADS); /* Zero(pw->aqMask); */ pw->pchWord = pchWord; pw->cchLength = cchLength; for (i = 0; i < ALPHABET; i++) { pw->aqMask[alPhrase[i].iq] |= (Quad)cchFrequency[i] << alPhrase[i].uShift; }}/* AddWords -- build the list of candidates */voidAddWords(void) { char * pch = pchDictionary; /* walk through the dictionary */ cpwCand = 0; while (*pch) { if ((pch[1] >= cchMinLength && pch[1]+cchMinLength <= cchPhraseLength) || pch[1] == cchPhraseLength) BuildWord(pch+2); pch += *pch; } fprintf(stdout, "%d candidates\n", cpwCand);}void DumpCandidates(void) { unsigned u; for (u = 0; u < cpwCand; u++) printf(StringFormat, apwCand[u]->pchWord, (u % 4 == 3) ? '\n' : ' '); printf("\n");}PWord apwSol[MAXSOL]; /* the answers */int cpwLast;Debug(void DumpWord(Quad * pq) { int i; Quad q; for (i = 0; i < ALPHABET; i++) { if (alPhrase[i].uFrequency == 0) continue; q = pq[alPhrase[i].iq]; if (alPhrase[i].uShift) q >>= alPhrase[i].uShift; q &= alPhrase[i].uBits; while (q--) putchar('a'+i); } putchar(' ');}) /* End of debug code */void DumpWords(void) { int i; for (i = 0; i < cpwLast; i++) wprint(apwSol[i]->pchWord); printf("\n");}Stat(unsigned long ulHighCount; unsigned long ulLowCount;)jmp_buf jbAnagram;#define OneStep(i) \ if ((aqNext[i] = pqMask[i] - pw->aqMask[i]) & aqMainSign[i]) { \ ppwStart++; \ continue; \ }voidFindAnagram(Quad * pqMask, PPWord ppwStart, int iLetter){ Quad aqNext[MAX_QUADS]; register PWord pw; Quad qMask; unsigned iq; PPWord ppwEnd = &apwCand[0]; ppwEnd += cpwCand; ; if (HaltProcessing()) longjmp(jbAnagram, 1); Debug(printf("Trying :"); DumpWord(pqMask); printf(":\n");) for (;;) { iq = alPhrase[achByFrequency[iLetter]].iq; qMask = alPhrase[achByFrequency[iLetter]].uBits << alPhrase[achByFrequency[iLetter]].uShift; if (pqMask[iq] & qMask) break; iLetter++; } Debug(printf("Pivoting on %c\n", i2ch(achByFrequency[iLetter]));) while (ppwStart < ppwEnd) { /* Half of the program execution */ pw = *ppwStart; /* time is spent in these three */ Stat(if (++ulLowCount == 0) ++ulHighCount;)#if MAX_QUADS > 0 OneStep(0); /* lines of code. */#endif#if MAX_QUADS > 1 OneStep(1);#endif#if MAX_QUADS > 2 OneStep(2);#endif#if MAX_QUADS > 3 OneStep(3);#endif#if MAX_QUADS > 4 @@"Add more unrolling steps here, please."@@#endif /* If the pivot letter isn't present, defer this word until later */ if ((pw->aqMask[iq] & qMask) == 0) { *ppwStart = *--ppwEnd; *ppwEnd = pw; continue; } /* If we get here, this means the word fits. */ apwSol[cpwLast++] = pw; if (cchPhraseLength -= pw->cchLength) { /* recurse */ Debug(DumpWords();) /* The recursive call scrambles the tail, so we have to be * pessimistic. */ ppwEnd = &apwCand[0]; ppwEnd += cpwCand; FindAnagram(&aqNext[0], ppwStart, iLetter); } else DumpWords(); /* found one */ cchPhraseLength += pw->cchLength; --cpwLast; ppwStart++; continue; } ;}int Cdecl CompareFrequency(char *pch1, char *pch2) { return auGlobalFrequency[*pch1] < auGlobalFrequency[*pch2] ? -1 : auGlobalFrequency[*pch1] == auGlobalFrequency[*pch2] ? 0 : 1;}void SortCandidates(void) { int i; /* Sort the letters by frequency */ for (i = 0; i < ALPHABET; i++) achByFrequency[i] = i; qsort(achByFrequency, ALPHABET, sizeof(char), (int (*)(const void *, const void *))CompareFrequency); fprintf(stdout, "Order of search will be "); for (i = 0; i < ALPHABET; i++) fputc(i2ch(achByFrequency[i]), stdout); fputc('\n', stdout);}int fInteractive;char * GetPhrase(char * pch) { if (fInteractive) printf(">"); fflush(stdout); if (gets(pch) == NULL) {#ifdef PLUS_STATS PrintDerefStats(stdout); PrintHeapSize(stdout);#endif /* PLUS_STATS */ exit(0); } return(pch);}char achPhrase[255];int Cdecl main(int cpchArgc, char **ppchArgv) { if (cpchArgc != 2 && cpchArgc != 3) Fatal("Usage: anagram dictionary [length]\n", 0); if (cpchArgc == 3) cchMinLength = atoi(ppchArgv[2]); fInteractive = isatty(1); ReadDict(ppchArgv[1]); while (GetPhrase(&achPhrase[0]) != NULL) { if (isdigit(achPhrase[0])) { cchMinLength = atoi(achPhrase); printf("New length: %d\n", cchMinLength); } else if (achPhrase[0] == '?') { DumpCandidates(); } else { BuildMask(&achPhrase[0]); AddWords(); if (cpwCand == 0 || cchPhraseLength == 0) continue; Stat(ulHighCount = ulLowCount = 0;) cpwLast = 0; SortCandidates(); if (setjmp(jbAnagram) == 0) FindAnagram(&aqMainMask[0], &apwCand[0], 0); Stat(printf("%lu:%lu probes\n", ulHighCount, ulLowCount);) } } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -