# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # Makefile # ReadMe # icecream.h # amy.C # amy2.C # amyhash.C # buckettest.C # concordance.C # dijkstra.C # findtest.C # game.C # heaptest.C # icecream.C # insertiontest.C # letterfreq.C # listtest.C # ltest.C # mergeSort.C # mergetest.C # orderedTest.C # parsetest.C # polytest.C # quicktest.C # searchtreetest.C # selectiontest.C # sieve.C # slowBucket.C # spellcheck.C # spellcheckList.C # traversaltest.C # treetest.C # wordlengthfreq.C # concordance.in # game.in # concordance.out # dijkstra.out # game.out # letterfreq.out # parse.out # poly.out # sieve.out # traversal.out # wordlengthfreq.out # echo x - Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' X# X# Makefile X# This makefile compiles the code for testing the code in X# Classic Data Structures in C++, by Timothy A. Budd. The X# user must select the appropriate macros, depending on X# the compiler used. X# INCL should be the directory where the data structure files X# are located X# X X# Unix Macros XINCL = ../orlib XLIB = -lm XXLIBS = /usr/local/cfront/lib/libC.a XSEP = / XCC = g++ XCFLAGS = -I $(INCL) XOBJ = .o XEXE = XNAME = -o $@ XRM = rm -fr XDIFF = diff XCOPY = cp X X# Borland C++ Macros X#INCL = ..\code X#LIB = X#SEP = \\ X#CC = bcc X#CFLAGS = -I$(INCL) -P -N -D__GNUG__ X#OBJ = .obj X#EXE = .exe X#NAME = -e$@ X#RM = del X#DIFF = fc X#COPY = copy X X# c++ compile rule X.SUFFIXES: .C X X.C.o: X $(CC) $(CFLAGS) -c $< X X# make test will run through all test cases Xall: test1 test2 test3 test4 X X# bundle Xbundle: clean X shar Makefile ReadMe *.h *.C *.in *.out >/tmp/tests X Xfoo$(EXE): foo$(OBJ) X $(CC) $(CFLAGS) -o foo$(EXE) foo$(OBJ) X Xclean: X $(RM) *$(OBJ) X $(RM) ptrepository X $(RM) polytest$(EXE) letterfreq$(EXE) sieve$(EXE) X $(RM) wordlengthfreq$(EXE) game$(EXE) X $(RM) traversaltest$(EXE) parsetest$(EXE) findtest$(EXE) X $(RM) mergetest$(EXE) selectiontest$(EXE) insertiontest$(EXE) X $(RM) listtest$(EXE) heaptest$(EXE) treetest$(EXE) X $(RM) quicktest$(EXE) concordance$(EXE) dijkstra$(EXE) X Xtest1: polytest$(EXE) letterfreq$(EXE) sieve$(EXE) wordlengthfreq$(EXE) \ X game$(EXE) X polytest > out X $(DIFF) out poly.out X letterfreq < letterfreq.C > out X $(DIFF) out letterfreq.out X sieve > out X $(DIFF) out sieve.out X wordlengthfreq < wordlengthfreq.C > out X $(DIFF) out wordlengthfreq.out X game < game.in > out X $(DIFF) out game.out X Xtest2: traversaltest$(EXE) parsetest$(EXE) findtest$(EXE) mergetest$(EXE) X traversaltest > out X $(DIFF) out traversal.out X parsetest > out X $(DIFF) out parse.out X findtest X mergetest X Xtest3: selectiontest$(EXE) insertiontest$(EXE) listtest$(EXE) \ X heaptest$(EXE) treetest$(EXE) X selectiontest X insertiontest X listtest X heaptest X treetest X Xtest4: quicktest$(EXE) concordance$(EXE) dijkstra$(EXE) X quicktest X concordance < concordance.in > out X $(DIFF) out concordance.out X dijkstra > out X $(DIFF) out dijkstra.out X Xpolytest$(EXE): polytest$(OBJ) X $(CC) $(CFLAGS) $(NAME) polytest$(OBJ) $(LIB) X Xletterfreq$(EXE): letterfreq$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) letterfreq$(OBJ) string$(OBJ) $(LIB) X Xsieve$(EXE): sieve$(OBJ) bitvec$(OBJ) X $(CC) $(CFLAGS) $(NAME) sieve$(OBJ) bitvec$(OBJ) $(LIB) X Xamy$(EXE): amy$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) amy$(OBJ) string$(OBJ) X Xamy2$(EXE): amy2$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) amy2$(OBJ) string$(OBJ) $(LIB) X Xamyhash$(EXE): amyhash$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) amyhash$(OBJ) string$(OBJ) $(LIB) X Xwordlengthfreq$(EXE): wordlengthfreq$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) wordlengthfreq$(OBJ) string$(OBJ) $(LIB) X Xgame$(EXE): game$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) game$(OBJ) string$(OBJ) $(LIB) X Xtraversaltest$(EXE): traversaltest$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) traversaltest$(OBJ) string$(OBJ) $(LIB) X Xparsetest$(EXE): parsetest$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) parsetest$(OBJ) string$(OBJ) $(LIB) X Xselectiontest$(EXE): selectiontest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) selectiontest$(OBJ) random$(OBJ) $(LIB) X Xinsertiontest$(EXE): insertiontest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) insertiontest$(OBJ) random$(OBJ) $(LIB) X Xheaptest$(EXE): heaptest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) heaptest$(OBJ) random$(OBJ) $(LIB) X Xtreetest$(EXE): treetest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) treetest$(OBJ) random$(OBJ) $(LIB) X XorderedTest$(EXE): orderedTest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) orderedTest$(OBJ) random$(OBJ) $(LIB) X Xlisttest$(EXE): listtest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) listtest$(OBJ) random$(OBJ) $(LIB) X Xquicktest$(EXE): quicktest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) quicktest$(OBJ) random$(OBJ) $(LIB) X Xfindtest$(EXE): findtest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) findtest$(OBJ) random$(OBJ) $(LIB) X XspellcheckList$(EXE): spellcheckList$(OBJ) string$(OBJ) bitvec$(OBJ) \ X split$(OBJ) X $(CC) $(CFLAGS) $(NAME) spellcheckList$(OBJ) string$(OBJ) \ X bitvec$(OBJ) split$(OBJ) $(LIB) X Xspellcheck$(EXE): spellcheck$(OBJ) string$(OBJ) bitvec$(OBJ) split$(OBJ) X $(CC) $(CFLAGS) $(NAME) spellcheck$(OBJ) string$(OBJ) \ X bitvec$(OBJ) split$(OBJ) $(LIB) X X# this one didn't work with g++ Xbuckettest$(EXE): buckettest$(OBJ) random$(OBJ) X $(CC) $(CFLAGS) $(NAME) buckettest$(OBJ) random$(OBJ) X Xmergetest$(EXE): mergetest$(OBJ) mergeSort$(OBJ) random$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) mergetest$(OBJ) mergeSort$(OBJ) \ X random$(OBJ) string$(OBJ) $(LIB) X Xconcordance$(EXE): concordance$(OBJ) string$(OBJ) split$(OBJ) bitvec$(OBJ) X $(CC) $(CFLAGS) $(NAME) concordance$(OBJ) string$(OBJ) \ X split$(OBJ) bitvec$(OBJ) $(LIB) X Xdijkstra$(EXE): dijkstra$(OBJ) string$(OBJ) X $(CC) $(CFLAGS) $(NAME) dijkstra$(OBJ) string$(OBJ) X X# X# files copied from data structure area X# X Xstring$(OBJ): $(INCL)$(SEP)string$(OBJ) X $(COPY) $(INCL)$(SEP)string$(OBJ) . X Xbitvec$(OBJ): $(INCL)$(SEP)bitvec$(OBJ) X $(COPY) $(INCL)$(SEP)bitvec$(OBJ) . X Xrandom$(OBJ): $(INCL)$(SEP)random$(OBJ) X $(COPY) $(INCL)$(SEP)random$(OBJ) . X Xsplit$(OBJ): $(INCL)$(SEP)split$(OBJ) X $(COPY) $(INCL)$(SEP)split$(OBJ) . END-of-Makefile echo x - ReadMe sed 's/^X//' >ReadMe << 'END-of-ReadMe' XThis directory contains the test programs Xassociated with X ``Classic Data Structures in C++'', by Tim Budd X XThe files have been tested with Cfront (version 3), g++ (version 2.5) Xand Borland Turbo-C++. X XFrom time to time changes in the compilers alter the behavior of Xtest programs. I have tried to keep the following up to date, but Xno guarantees can be given. X X===================When using Cfront X XCFRONT demands that some of the implementation files be found in files Xwith extension *.c , while g++ and borland want exactly the same information Xon the *.h files. X XI have been unable to get the ``concordance'' test program to compile Xwith cfront, however all other test programs work. X X===================When using g++ X Xtests 1, 2 and 3 work, test 4 fails because the current version of g++ Xdoes not like any data structure which maintains a collection of Xreferences, instead of a collection of pointers. X X(worse, the error messages are very cryptic in this case). X X===================When using Borland Turbo-C++ X Xno problems reported END-of-ReadMe echo x - icecream.h sed 's/^X//' >icecream.h << 'END-of-icecream.h' X# include "string.h" X Xclass iceCreamRecord { Xpublic: X X // constructors X iceCreamRecord(); X iceCreamRecord(const string & namestr, const string & flavorstr); X X // field access X string name() const; X string flavor() const; X X void operator = (const iceCreamRecord & right); X Xprivate: X char nameField[20]; X char flavorField[20]; X}; X Xint isEmpty(const iceCreamRecord & x); X Xint operator == (const iceCreamRecord & left, const iceCreamRecord & right); X Xostream & operator << (ostream & out, iceCreamRecord & right); END-of-icecream.h echo x - amy.C sed 's/^X//' >amy.C << 'END-of-amy.C' X# include X# include X# include X X// X// Amy's program to maintain club finances X// X Xvoid clubFinances() { X dictionary data(0.0); X X string name; X double amount; X double totalDues = 0; // total dues paid X X // loop while there are records X while (cin >> name >> amount) { X // add the new amount to the data record X data[name] += amount; X // add to the total dues paid X totalDues += amount; X } X X // report the result X cout << "Dues paid:\n"; X dictionaryIterator itr(data); X for (itr.init(); ! itr; itr++) X cout << itr().key() << ": $" << itr().value() << '\n'; X cout << "total dues paid: $" << totalDues << '\n'; X} X Xmain() { X clubFinances(); X} END-of-amy.C echo x - amy2.C sed 's/^X//' >amy2.C << 'END-of-amy2.C' X// X// amy's program to compute the club's finances X// X X# include X# include X# include X Xint namehash(const string & name) X{ // perfect hash function for X // alfred, alex, alice, amy, any and ann X return (name[2] - 'a') % 6; X} X Xmain() { X hashVector data(6, & namehash, 0.0); X X string name; X double amount; X double totalDues = 0; // total dues paid X X // loop while there are records X while (cin >> name >> amount) { X // add the new amount to the data record X data[name] += amount; X // add to the total dues paid X totalDues += amount; X } X X // report the result X cout << "Dues paid:\n"; X cout << " alfred: $" << data["alfred"] << '\n'; X cout << " alex: $" << data["alex"] << '\n'; X cout << " alice: $" << data["alice"] << '\n'; X cout << " amy: $" << data["amy"] << '\n'; X cout << " andy: $" << data["andy"] << '\n'; X cout << " ann: $" << data["ann"] << '\n'; X cout << "total dues paid: $" << totalDues << '\n'; X X return 0; X} X END-of-amy2.C echo x - amyhash.C sed 's/^X//' >amyhash.C << 'END-of-amyhash.C' X# include X# include X X# include X// X// Amy's program to maintain club finances X// X Xunsigned int namehash(const string & name) X{ X return name[2] - 'a'; X} X Xvoid clubFinances() { X table data(5, & namehash, 0.0); X X string name; X double amount; X double totalDues = 0; // total dues paid X X // loop while there are records X while (cin >> name >> amount) { X // add the new amount to the data record X data[name] += amount; X // add to the total dues paid X totalDues += amount; X } X X // report the result X cout << "Dues paid:\n"; X tableIterator itr(data); X for (itr.init(); ! itr; itr++) X cout << itr().key() << ": $" << itr().value() << '\n'; X cout << "total dues paid: $" << totalDues << '\n'; X} X Xmain() { X clubFinances(); X return 0; X} END-of-amyhash.C echo x - buckettest.C sed 's/^X//' >buckettest.C << 'END-of-buckettest.C' X# include X# include X# include X# include X Xunsigned int hf(const int & x) X{ X return x >> 4; X} X Xint main() { X Xrandom rand; Xunsigned int max = 10000; Xvector x(max); X X for (int i = 0; i < max; i++) X x[i] = rand.between(0,16000); X X bucketSort(x, (unsigned int) 1000, & hf); X X int low = 0; X for (i = 0; i < max; i++) { X if (x[i] < low) { X cerr << "sort failed -- out of order\n"; X return 1; X } X low = x[i]; X } X return 0; X X} X END-of-buckettest.C echo x - concordance.C sed 's/^X//' >concordance.C << 'END-of-concordance.C' X# include X# include X# include X# include X# include X# include X# include X# include X Xvoid makeConcordance(istream & in, X orderedDictionary > & concordance) X{ // read from the indicated input stream, making a concordance X string line(256); X vector words(1, "x"); X X for (int lineNumber = 1; line.getline(in); lineNumber++) { X split(line, " .;:?,", words); X vectorIterator witr(words); X for (witr.init(); ! witr; ++witr) { X concordance[witr()].add(lineNumber); X } X } X} X Xvoid printConcordance X (orderedDictionary > & concordance) X{ // print out the values in a concordance X orderedDictionaryIterator > ditr(concordance); X for (ditr.init(); ! ditr; ++ditr) { X cout << ditr().key() << ": "; X setList slist(ditr().value()); X listIterator litr(slist); X for (litr.init(); ! litr; ++litr) X cout << litr() << " "; X cout << '\n'; X } X} X Xvoid generateConcordance(istream & in) X{ // generate a concordance for the text given by the input stream X orderedDictionary > concordance; X // first make the concordance X makeConcordance(in, concordance); X // then print it out X printConcordance(concordance); X} X Xmain() X{ X generateConcordance(cin); X return 0; X} END-of-concordance.C echo x - dijkstra.C sed 's/^X//' >dijkstra.C << 'END-of-dijkstra.C' X# include X X# include X# include X# include X# include X X// g++ doesn't like the first typedef -- but accepts the second X// who can figure?? X// typedef labeledVertex node; X# define node labeledVertex Xtypedef cAssociation *> arc; X Xvoid dijkstra(node * start, dictionary & distances) X{ X // make sure distances dictionary is empty X distances.deleteAllValues(); X X // process a priority queue of distances to nodes X priorityQueueList que; X que.add(arc(0.0, start)); X X // continually remove smallest element from queue X while (! que.isEmpty()) { X arc neighbor = que.deleteMin(); X node * neighborNode = neighbor.value(); X // if neighbor has not already been seen, X // process it X if (! distances.includesKey(neighborNode)) { X double dist = neighbor.key(); X distances[neighborNode] = dist; X dictionaryIterator itr(neighborNode->arcs); X for (itr.init(); ! itr; ++itr) { X que.add(arc(dist + itr()->value(), itr()->key())); X} X } X } X} X Xmain() { X X// make the initial vertices Xnode pendleton("pendleton"); Xnode pensacola("pensacola"); Xnode peoria("peoria"); Xnode phoenix("phoenix"); Xnode pierre("pierre"); Xnode pittsburg("pittsburg"); Xnode princeton("princeton"); Xnode pueblo("pueblo"); X X// create the initial links Xpendleton.addArc(& phoenix, 4); pendleton.addArc(& pueblo, 8); Xpensacola.addArc(& phoenix, 5); Xpeoria.addArc(& pittsburg, 5); peoria.addArc(& pueblo, 3); Xphoenix.addArc(& peoria, 4); phoenix.addArc(& pittsburg, 10); Xphoenix.addArc(&pueblo,3); Xpierre.addArc(& pendleton, 2); Xpittsburg.addArc(& pensacola, 4); Xprinceton.addArc(& pittsburg, 2); Xpueblo.addArc(& pierre, 3); X Xdictionary dist; X Xdijkstra(& pierre, dist); X XdictionaryIterator itr(dist); Xfor (itr.init(); ! itr; ++itr) X cout << itr()->key()->value << " : " << itr()->value() << '\n'; X Xreturn 0; X} END-of-dijkstra.C echo x - findtest.C sed 's/^X//' >findtest.C << 'END-of-findtest.C' X# include X# include X# include X X Xint main() { X Xrandom rand; Xint max = 10000; Xvector x(max); X X // make a vector of numbers X for (int i = 0; i < max; i++) X x[i] = rand.between(0,16000); X X // find the meadian X int m = findElement(x, max/2, 0, max-1); X X cout << "meadian is " << m << '\n'; X X return 0; X} X END-of-findtest.C echo x - game.C sed 's/^X//' >game.C << 'END-of-game.C' X// X// guess the animal game X// X X# include X# include X# include X# include X Xnode * root; X Xint answer() { X // get yes no answer X string ans(100); X ans.getline(cin); X if ((ans[0] == 'y') || (ans[0] == 'Y')) X return 1; X else if ((ans[0] == 'n') || (ans[0] == 'N')) X return 0; X cout << "please answer yes or no.\n"; X return answer(); X} X Xvoid learnNewAnimal(node * current) X{ // learn about a new animal type X X string currentanimal = current->value; X cout << "what is your animal?\n"; X string newanimal(200); X newanimal.getline(cin); X cout << "what is a yes/no question that I can use to tell a " X << current->value << " from a " << newanimal << " ?\n"; X string newquestion(200); X newquestion.getline(cin); X cout << "for a " << newanimal << " is the answer yes or no?\n"; X node * node1 = new node(newanimal); X node * node2 = new node(currentanimal); X // make sure allocation worked X assert(node1 && node2); X X if (answer()) { X current->left(node1); X current->right(node2); X } X else { X current->left(node2); X current->right(node1); X } X current->value = newquestion; X} X Xmain() { X // initialize the database with one animal X root = new node("cat"); X node * current = root; X // now start the game X cout << "let's play guess the animal.\n"; X while (current) { X // if current node has children it is a question X if (current->left()) { X cout << current->value << '\n'; X if (answer()) X current = current->left(); X else X current = current->right(); X } X // if no children it is an answer X else { X cout << "I know. Is it a " << current->value << " ?\n"; X if (answer()) X cout << "I won.\n"; X else { X // we didn't get it. X // time to learn something X learnNewAnimal(current); X } X cout << "Try again?\n"; X if (answer()) X current = root; X else X return 0; X } X } X} END-of-game.C echo x - heaptest.C sed 's/^X//' >heaptest.C << 'END-of-heaptest.C' X X# include X# include X# include X# include X Xint main() { X Xrandom rand; Xunsigned int max = 10; Xvector x(max); X X for (int i = 0; i < max; i++) { X x[i] = rand.between(0,16000); X } X X heapSort(x); X X int high = 16000; X for (i = 0; i < max; i++) { X if (high < x[i]) { X cerr << "sort failed -- out of order\n"; X return 1; X } X high = x[i]; X } X return 0; X} X END-of-heaptest.C echo x - icecream.C sed 's/^X//' >icecream.C << 'END-of-icecream.C' X# include X# include X# include "icecream.h" X XiceCreamRecord::iceCreamRecord() X{ // just put empty strings in both locations X nameField[0] = '\0'; X flavorField[0] = '\0'; X} X XiceCreamRecord::iceCreamRecord(const string & namestr, const string & flavorstr) X{ // copy values into the two fields X for (unsigned int i = 0; namestr[i] != '\0'; i++) X nameField[i] = namestr[i]; X nameField[i] = '\0'; X for (i = 0; flavorstr[i] != '\0'; i++) X flavorField[i] = flavorstr[i]; X flavorField[i] = '\0'; X} X Xstring iceCreamRecord::name() const X{ // return name field made into a string X string result(nameField); X return result; X} X Xstring iceCreamRecord::flavor() const X{ // return flavor field made into a string X string result(flavorField); X return result; X} X Xint isEmpty(const iceCreamRecord & x) X{ // field is empty if it has no name component X string empty; X return x.name() == empty; X} X Xint operator == (const iceCreamRecord & left, const iceCreamRecord & right) X{ // equality between records based only on name X return left.name() == right.name(); X} X Xvoid iceCreamRecord::operator = (const iceCreamRecord & right) X{ X strcpy(nameField, right.nameField); X strcpy(flavorField, right.flavorField); X} X Xostream & operator << (ostream & out, iceCreamRecord & right) X{ X out << right.name(); X out << " and "; X out << right.flavor(); X //out << right.name() << " and " << right.flavor(); X return out; X} END-of-icecream.C echo x - insertiontest.C sed 's/^X//' >insertiontest.C << 'END-of-insertiontest.C' X# include X X# include X# include X Xint main() { X random rand; X const unsigned int max = 1000; X vector x(max); X X for (int i = 0; i < max; i++) X x[i] = rand.between(0,16000); X X X insertionSort(x); X X int low = 0; X for (i = 0; i < max; i++) { X if (x[i] < low) { X cerr << "sort failed -- out of order\n"; X return 1; X } X low = x[i]; X } X return 0; X} X END-of-insertiontest.C echo x - letterfreq.C sed 's/^X//' >letterfreq.C << 'END-of-letterfreq.C' X# include X# include X# include X# include X# include X Xvoid letterOccurrences(boundedVector & counts, const string & text) X{ X // make sure the upper and lower bound on counts X // array is what we expect X assert (counts.lowerBound() == 'a'); X assert (counts.upperBound() == 'z'); X X // loop over the text string X // considering each character in turn X for (int i = 0; text[i] != '\0'; i++) { X char c = text[i]; X if (isupper(c)) X c = tolower(c); X if (islower(c)) X counts[c]++; X } X} X Xvoid computeWordOccurrences() X{ X // declare a vector indexed from 'a' to 'z' initialized to zero X boundedVector counts('a', 'z', 0); X string word; X X // read and analyze the input X while (cin >> word) X letterOccurrences(counts, word); X X // then print the results X for (char c = 'a'; c <= 'z'; c++) X cout << "letter " << c << " occurrences " << counts[c] << '\n'; X} X Xmain() X{ X computeWordOccurrences(); X return 0; X} END-of-letterfreq.C echo x - listtest.C sed 's/^X//' >listtest.C << 'END-of-listtest.C' X X# include X# include X# include X# include X Xint main() { X Xrandom rand; Xunsigned int max = 1000; Xvector x(max); X X for (int i = 0; i < max; i++) X x[i] = rand.between(0,16000); X X listInsertionSort(x); X X int low = 0; X for (i = 0; i < max; i++) { X if (x[i] < low) { X cerr << "sort failed -- out of order\n"; X return 1; X } X low = x[i]; X } X X return 0; X} X END-of-listtest.C echo x - ltest.C sed 's/^X//' >ltest.C << 'END-of-ltest.C' X// X// just a simple test of lists X// X X# include X Xlist foo; X Xmain() { X foo.add(2); X} X END-of-ltest.C echo x - mergeSort.C sed 's/^X//' >mergeSort.C << 'END-of-mergeSort.C' X# include X# include X# include X# include X Xstring tempFileName(int i) X{ // create a temporary file name from integer i X string name = "/tmp/mergeSortTemp"; X string num = ""; X // first convert i into a string name X while (i > 0) { X char val = (i % 10) + '0'; X num = string(val) + num; X i = i / 10; X } X // then append the string version of i to name X name += num; X return name; X} X Xint topFile = 0; X Xvoid copyToTemporary(vector & words) X{ // copy the sorted list of words to a new temporary file X X // first sort the list of words X selectionSort(words); X X // then copy to temporary file X topFile = topFile + 1; X string t1(tempFileName(topFile)); X ofstream tempfile(t1); X vectorIterator witr(words); X for (witr.init(); ! witr; witr++) X tempfile << witr() << '\n'; X} X Xvoid phase1(istream & infile) X{ // phase 1 of heap sort X // read all lines from input file, X // and separate into temporary files X string buffer(200); X const int wordVectorSize = 1000; X vector words(wordVectorSize); X int wordcount; X X // read words and put them into temporary files X wordcount = 0; X while (buffer.getline(infile)) { X words[wordcount++] = buffer; X if (wordcount >= wordVectorSize) { X copyToTemporary(words); X wordcount = 0; X } X } X // if wordcount is greater than zero, it means X // there are leftover words X if (wordcount > 0) { X words.setSize(wordcount); X copyToTemporary(words); X } X} X Xvoid mergeFiles(istream & in1, istream & in2, ostream & out) X{ // merge two sorted input streams into one output stream X string word1(200); X string word2(200); X int flag1 = 0; X int flag2 = 0; X X // get first words X if (word1.getline(in1)) X flag1 = 1; X if (word2.getline(in2)) X flag2 = 1; X X while ((flag1 != 0) && (flag2 != 0)) { X // write out smallest word and refill word X if (word1 < word2) { X out << word1 << '\n'; X if (! (word1.getline(in1))) X flag1 = 0; X } X else { X out << word2 << '\n'; X if (! (word2.getline(in2))) X flag2 = 0; X } X } X X // copy remainder from files X while (flag1 != 0) { X out << word1 << '\n'; X if (! (word1.getline(in1))) X flag1 = 0; X } X X while (flag2 != 0) { X out << word2 << '\n'; X if (! (word2.getline(in2))) X flag2 = 0; X } X} X Xvoid mergeSort(istream & infile, ostream & outfile) X{ // sort input stream, placing result on output stream X topFile = 0; X X // phase 1, break input into temporary files X phase1(infile); X X // phase 2, merge files back together X int i = 1; X while (i < topFile) { X // open input files X ifstream temp1((const char *) tempFileName(i)); X i++; X ifstream temp2((const char *) tempFileName(i)); X i++; X X // open output file X topFile++; X ofstream temp3((const char *) tempFileName(topFile)); X X // merge files together X mergeFiles(temp1, temp2, temp3); X } X X // phase 3, copy from final temporary file to output file X ifstream from((const char *) tempFileName(topFile)); X char ch; X while (from.get(ch)) X outfile.put(ch); X} X END-of-mergeSort.C echo x - mergetest.C sed 's/^X//' >mergetest.C << 'END-of-mergetest.C' X# include X# include X# include X# include X Xvoid mergeSort(istream &, ostream &); Xstring inputFileName = "/tmp/mergedatainput"; Xstring outputFileName = "/tmp/mergedataoutput"; X X Xvoid makeInputFile() { X random rand; X ofstream ofile(inputFileName); X X for (int i = 0; i < 10000; i++) X ofile << rand.between(1,16000) << '\n'; X} X Xvoid doSort() { X ifstream inf(inputFileName); X ofstream ouf(outputFileName); X mergeSort(inf, ouf); X } X Xint checkSort() { X ifstream inf(outputFileName); X string word1(256); X string word2(256); X X word1.getline(inf); X while (word2.getline(inf)) { X if (word2 < word1) { X cout << "sort failed, out of order"; X return 1; X } X word1 = word2; X } X cout << "merge sort successful\n"; X return 0; X} X Xint main() { X // first make a file of random values X makeInputFile(); X X // sort the file X doSort(); X X // now make sure file is sorted X return checkSort(); X} X END-of-mergetest.C echo x - orderedTest.C sed 's/^X//' >orderedTest.C << 'END-of-orderedTest.C' X// X// testing ordered vectors X// X X# include X# include X# include X Xint main() { X Xrandom rand; Xunsigned int max = 100; XorderedVector x; X X // add a bunch of new numbers X for (int i = 0; i < max; i++) X x.add(rand.between(0,16000)); X X // now see if they are ordered X int low = 0; X for (i = 0; i < max; i++) { X if (x[i] < low) { X cerr << "sort failed -- out of order\n"; X return 1; X } X low = x[i]; X } X return 0; X} X X END-of-orderedTest.C echo x - parsetest.C sed 's/^X//' >parsetest.C << 'END-of-parsetest.C' X// X// operator precedence parsing example X// X Xenum operators {identifier, leftparen, plus, minus, times, divide}; X X# include X X# include X X# include X Xclass parseInformation { Xpublic: X // data areas, type, other information X operators type; X string name; X X // constructors X parseInformation(); X parseInformation(char n); X parseInformation(operators); X}; X XparseInformation::parseInformation() : type(identifier) X{ X} X XparseInformation::parseInformation(char n) : type(identifier) X{ X name = n; X} X XparseInformation::parseInformation(operators t) : type(t) X{ X // no further initialization X} X X# include X# include X Xint isAlphabetic(char c) X{ X return (c >= 'a') && (c <= 'z'); X} X Xvoid doBinary(operators theOp, stackList *> & operandStack) X{ // build a binary operator node by combining child nodes X node * right = operandStack.pop(); X node * left = operandStack.pop(); X node * newNode = X new node(theOp, left, right); X assert(newNode != 0); X operandStack.push(newNode); X} X Xvoid processOp(operators theOp, stackList & operatorStack, X stackList *> & operandStack) X{ X // pop stack while operators have higher precedence X while ((! operatorStack.isEmpty()) && (theOp < operatorStack.top())) X doBinary(operatorStack.pop(), operandStack); X X // then push operator X operatorStack.push(theOp); X} X Xnode * parse(const string & inputString) X{ X // stacks for both operators and operands X stackList operatorStack; X stackList *> operandStack; X X int i = 0; X while (inputString[i] != '\0') X if (isAlphabetic(inputString[i])) { X node * newNode = X new node(parseInformation(inputString[i++])); X assert(newNode != 0); X operandStack.push(newNode); X } X else X switch(inputString[i++]) { X case '(': X operatorStack.push(leftparen); X break; X case ')': X while (operatorStack.top() != leftparen) X doBinary(operatorStack.pop(), operandStack); X operandStack.pop(); // left paren X break; X case '+': X processOp(plus, operatorStack, operandStack); X break; X case '-': X processOp(minus, operatorStack, operandStack); X break; X case '*': X processOp(times, operatorStack, operandStack); X break; X case '/': X processOp(divide, operatorStack, operandStack); X break; X } X X while (! operatorStack.isEmpty()) X doBinary(operatorStack.pop(), operandStack); X X // return the final expression X return operandStack.pop(); X} X X Xmain() X{ X node * result = parse("a + b * c"); X X // do a postorder traversal of result X postorderTreeTraversal itr(result); X for (itr.init(); ! itr; itr++) X switch(itr().type) { X case identifier: Xcout << "identifier " << itr().name << '\n'; break; X case plus: cout << " plus node\n"; break; X case minus: cout << " minus node\n"; break; X case times: cout << " times node\n"; break; X case divide: cout << " divide node\n"; break; X default: cout << "unknown node type\n"; break; X } X return 0; X} END-of-parsetest.C echo x - polytest.C sed 's/^X//' >polytest.C << 'END-of-polytest.C' X# include X# include X# include X X// instances of term represent polynomial terms Xclass term { Xpublic: X // constructor X term(int c, int p); X term(const term &); X X // operations X term operator * (const term & right); X term operator + (const term & right); X int operator == (const term & r); X double evalAt(double x); X Xprivate: X // data areas X int coefficient; X int power; X X // friends X friend class polynomial; X friend ostream & operator << (ostream &, const term &); X}; X Xterm::term(int c, int p) : power(p) X{ X coefficient = c; X} X Xterm::term(const term & x) : coefficient(x.coefficient), power(x.power) X{ X // nothing else X} X Xterm term::operator * (const term & right) X{ X return term(coefficient * right.coefficient, power + right.power); X} X Xterm term::operator + (const term & right) X{ X // check that powers match X assert (power == right.power); X return term(coefficient + right.coefficient, power); X} X Xint term::operator == (const term & r) X{ X return (coefficient == r.coefficient) && (power == r.power); X} X Xdouble term::evalAt(double x) X{ X return coefficient * pow(x, (double) power); X} X Xostream & operator << (ostream & out, const term & val) X{ X // don't print zero terms X if (val.coefficient == 0) X return out; X X // print the coefficient X out << val.coefficient; X X // print the exponent X switch(val.power) { X case 0: X break; // do nothing X case 1: X out << " X"; X break; X default: X out << " X^" << val.power; X break; X } X return out; X} X X# include X Xclass polynomial { Xpublic: X polynomial(); X polynomial(const polynomial & p); X polynomial(term & t); X polynomial(int one, int con); X polynomial(int two, int one, int con); X X // operations X void operator += (polynomial & right); X void operator *= (const term &); X double evalAt(double); X Xpublic: // cfront complains about private, why?? X // data areas X list terms; X X // friends X friend ostream & operator << (ostream &, polynomial &); X friend polynomial operator * (polynomial &, const polynomial &); X}; X Xpolynomial::polynomial() {} X Xpolynomial::polynomial(const polynomial & p) : terms(p.terms) {} X Xpolynomial::polynomial(term & t) X{ X terms.add(t); X} X Xpolynomial::polynomial(int one, int con) X{ X if (con) terms.add(term(con, 0)); X if (one) terms.add(term(one, 1)); X} X Xpolynomial::polynomial(int two, int one, int con) X{ X if (con) terms.add(term(con, 0)); X if (one) terms.add(term(one, 1)); X if (two) terms.add(term(two, 2)); X} X Xvoid polynomial::operator += (polynomial & right) X{ X // we loop over both left and right simultaneously X listIterator litr(terms); X listIterator ritr(right.terms); X X for (litr.init(), ritr.init(); !litr && ! ritr; litr++) { X // first add any leading right terms X while (!ritr && (litr().power < ritr().power)) { X litr.addBefore(ritr()); X ritr++; X } X if (!ritr && ritr().power == litr().power) { X litr = litr() + ritr(); X ritr++; X } X } X X // there may be left over right terms X while (! ritr) { X litr.addBefore(ritr()); X ritr++; X } X} X Xvoid polynomial::operator *= (const term & right) X{ X // loop over our terms, doing the multiplication X listIterator itr(terms); X for (itr.init(); !itr; itr++) { X itr = itr() * right; X } X} X Xpolynomial operator * (const polynomial & left, const term & right) X{ X polynomial result(left); X result *= right; X return result; X} X Xpolynomial operator * (polynomial & left, const polynomial & right) X{ X polynomial result; X listIterator itr(left.terms); X for (itr.init(); !itr; itr++) X result += right * itr(); X return result; X} X Xostream & operator << (ostream & out, polynomial & val) X{ X int first = 1; // used to avoid printing out initial + sign X X // iterate over terms X listIterator itr(val.terms); X for (itr.init(); !itr; itr++) { X if (! first) out << " + "; X first = 0; X out << itr(); X } X return out; X} X Xdouble polynomial::evalAt(double x) X{ X double sum = 0.0; X listIterator itr(terms); X for (itr.init(); !itr; itr++) X sum += itr().evalAt(x); X return sum; X} X Xmain() { X polynomial p(2, 3, 5); X polynomial q(4, 3); X X cout << p << '\n'; X cout << q << '\n'; X polynomial r = p * q; X cout << r << '\n'; X cout << p << '\n'; X cout << q << '\n'; X X return 0; X} X END-of-polytest.C echo x - quicktest.C sed 's/^X//' >quicktest.C << 'END-of-quicktest.C' X# include X# include X# include X Xint main() { X Xrandom rand; Xunsigned int max = 1000; Xvector x(max); X X for (int i = 0; i < max; i++) X x[i] = rand.between(0,16000); X X quackSort(x); X X int low = 0; X for (i = 0; i < max; i++) { X if (x[i] < low) { X cerr << "sort failed -- out of order\n"; X return 1; X } X low = x[i]; X } X return 0; X} X END-of-quicktest.C echo x - searchtreetest.C sed 's/^X//' >searchtreetest.C << 'END-of-searchtreetest.C' X// X// test search trees X// X X# include X X# include X# include X# include X XsearchTree data; Xvector rawdata(11); X Xvoid makeRawData() { Xrawdata[0] = "abigail"; Xrawdata[1] = "abner"; Xrawdata[2] = "adam"; Xrawdata[3] = "adela"; Xrawdata[4] = "agnes"; Xrawdata[5] = "alex"; Xrawdata[6] = "alice"; Xrawdata[7] = "allen"; Xrawdata[8] = "angela"; Xrawdata[9] = "arthur"; Xrawdata[10] = "audrey"; X} X Xvoid insertData() { X X data.deleteAllValues(); X for (int i = 0; i < 11; i++) { X data.add(rawdata[i]); X } X} X Xvoid displayData() { X searchTreeIterator itr(data); X for (itr.init(); ! itr; itr++) X cout << itr() << " "; X cout << '\n'; X} X Xmain() { XmakeRawData(); XinsertData(); XdisplayData(); X// includes test X cout << "includes fred?" << data.includes("fred") << '\n'; X cout << "includes arthur?" << data.includes("arthur") << '\n'; X X// now try a few deletes Xfor (int i = 0; i < 2; i++) { Xcout << "about to insert data\n"; X insertData(); Xcout << "removing " << i << '\n'; X data.remove(rawdata[i]); Xcout << "did remove " << i << '\n'; X displayData(); X } Xcout << "got here\n"; X} X END-of-searchtreetest.C echo x - selectiontest.C sed 's/^X//' >selectiontest.C << 'END-of-selectiontest.C' X# include X X# include X# include X Xint main() { X random rand; X const unsigned int max = 1000; X vector x(max); X X for (int i = 0; i < max; i++) X x[i] = rand.between(0,16000); X X X selectionSort(x); X X int low = 0; X for (i = 0; i < max; i++) { X if (x[i] < low) { X cerr << "sort failed -- out of order\n"; X return 1; X } X low = x[i]; X } X return 0; X} X END-of-selectiontest.C echo x - sieve.C sed 's/^X//' >sieve.C << 'END-of-sieve.C' X# include X# include X Xvoid sieve(bitVector & data) X{ X const unsigned int max = data.length(); X X // first initialize to all 1 bits X for (int i = 0; i < max; i++) X data.set(i); X X // now search for 1 bit positions X for (i = 2; i*i < max; i++) { X if (data.test(i)) { X // inv: i has no factors X for (int j = i + i; j < max; j += i) X data.clear(j); X // inv: all multiples of i have been cleared X } X // all set values smaller than i are prime X } X // inv: all set values are prime X} X X Xmain() { X const int size = 100; X bitVector result(size); X sieve(result); X X for (int i = 0; i < size; i++) X if (result.test(i)) X cout << i << ","; X cout << '\n'; X return 0; X} X END-of-sieve.C echo x - slowBucket.C sed 's/^X//' >slowBucket.C << 'END-of-slowBucket.C' X// X// test program for hash tables X// X X X# include X# include X# include "slowBucketSort.h" X X# include X# include X Xunsigned int hf(const int & x) X{ X return x >> 4; X} X Xmain() { X Xrandom rand; Xunsigned int max = 10000; Xvector x(max); X X for (int i = 0; i < max; i++) X x[i] = rand.between(0,16000); X X bucketSort(x, (unsigned int) 1000, hf); X X int low = 0; X for (i = 0; i < max; i++) { X if (x[i] < low) { X cerr << "out of order\n"; X return 1; X } X low = x[i]; X } X return 0; X} X END-of-slowBucket.C echo x - spellcheck.C sed 's/^X//' >spellcheck.C << 'END-of-spellcheck.C' X// X// spell check test case, using lists X// X X# include X# include X# include X# include X# include X# include X Xunsigned int wordhash(const string & word) X{ // compute hash value from word X int len = word.length(); X unsigned int result = 0; X if (len > 0) { X result = word[0] - 'a'; X if (len > 1) X result = result * 26 + (word[1] - 'b'); X } X return result; X} X Xvoid spellcheck(istream & dictionary, istream & infile, ostream & outfile) X{ string word(120); X string line(120); X setList misspelled; X setTable theDict(676, wordhash); X X // first read the dictionary into the table of words X while (dictionary >> word) X theDict.add(word); X X // then read the input file X // writing missing words to the output file X while (line.getline(infile)) { X // translate to lower case X toLower(line); X // split the line into individual words X vector words(10); X split(line, " \t\n.;?!", words); X // now loop over each indiviaul word X // if it is not in the dictionary then it may be wrong X vectorIterator itr(words); X for (itr.init(); ! itr; itr++) X if (! theDict.includes(itr())) X misspelled.add(itr()); X } X X // then output the list of misspelled words X listIterator itr(misspelled); X for (itr.init(); ! itr; itr++) X outfile << itr() << '\n'; X} X Xmain () { Xifstream wordfile("words"); Xspellcheck(wordfile, cin, cout); X} X END-of-spellcheck.C echo x - spellcheckList.C sed 's/^X//' >spellcheckList.C << 'END-of-spellcheckList.C' X// X// spell check test case, using lists X// X X# include X# include X# include X# include X# include X# include X Xvoid spellcheck(istream & dictionary, istream & infile, ostream & outfile) X{ string word(120); X string line(120); X setList theDict; X setList misspelled; X X // first read the dictionary into the table of words X while (dictionary >> word) X theDict.add(word); X X // then read the input file X // writing missing words to the output file X while (line.getline(infile)) { X // translate to lower case X toLower(line); X // split the line into individual words X vector words(10); X split(line, " \t\n.;?!", words); X // now loop over each individual word X // if it is not in the dictionary then it may be wrong X vectorIterator itr(words); X for (itr.init(); ! itr; itr++) { X if (! theDict.includes(itr())) X misspelled.add(itr()); X } X } X X // then output the list of misspelled words X listIterator itr(misspelled); X for (itr.init(); ! itr; itr++) X outfile << itr() << '\n'; X} X Xint main () { Xifstream wordfile("words"); Xspellcheck(wordfile, cin, cout); Xreturn 0; X} X END-of-spellcheckList.C echo x - traversaltest.C sed 's/^X//' >traversaltest.C << 'END-of-traversaltest.C' X# include X# include X# include X Xmain() { X node D("D"); X node E("E"); X node F("F"); X node G("G"); X node B("B", &D, &E); X node C("C", &F, &G); X node A("A", &B, &C); X X cout << "Pre order traversal \n"; X preorderTreeTraversal preitr(&A); X for (preitr.init(); ! preitr; preitr++) X cout << preitr(); X cout << '\n'; X X cout << "In order traversal \n"; X inorderTreeTraversal initr; X initr.setRoot(&A); X for (initr.init(); ! initr; initr++) X cout << initr(); X cout << '\n'; X X cout << "Post order traversal \n"; X postorderTreeTraversal postitr(&A); X for (postitr.init(); ! postitr; postitr++) X cout << postitr(); X cout << '\n'; X X cout << "Level order traversal \n"; X levelorderTreeTraversal levelitr(&A); X for (levelitr.init(); ! levelitr; levelitr++) X cout << levelitr(); X cout << '\n'; X return 0; X} END-of-traversaltest.C echo x - treetest.C sed 's/^X//' >treetest.C << 'END-of-treetest.C' X# include X# include X# include X# include X X Xint main() { X Xrandom rand; Xunsigned int max = 1000; Xvector x(max); X X for (int i = 0; i < max; i++) X x[i] = rand.between(0,16000); X X treeSort(x); X X int low = 0; X for (i = 0; i < max; i++) { X if (x[i] < low) { X cerr << "sort failed -- out of order\n"; X return 1; X } X low = x[i]; X } X return 0; X} X END-of-treetest.C echo x - wordlengthfreq.C sed 's/^X//' >wordlengthfreq.C << 'END-of-wordlengthfreq.C' X# include X# include X# include X X// tally occurrences of words by length in the standard input X// group all words larger than maximum index of first argument X// into bigwords category Xvoid wordLengthFreq(vector & counts, int & bigwords) X{ X const int lengthmax = counts.length(); X string word; X // compute the word frequencies X while (cin >> word) { X int wordlen = word.length(); X if (wordlen < lengthmax) X counts[wordlen]++; X else X bigwords++; X }} X Xmain() { X vector counts(20, 0); X int bigs = 0; X X wordLengthFreq(counts, bigs); X X for (int i = 0; i < 20; i++) X cout << "word size " << i << " count " << counts[i] << '\n'; X X cout << "big words " << bigs << '\n'; X return 0; X} END-of-wordlengthfreq.C echo x - concordance.in sed 's/^X//' >concordance.in << 'END-of-concordance.in' Xit was the best of times, Xit was the worst of times. X END-of-concordance.in echo x - game.in sed 's/^X//' >game.in << 'END-of-game.in' Xn Xdog Xdoes it bark? Xyes Xyes Xno Xno Xfish Xdoes it swim? Xyes Xno X END-of-game.in echo x - concordance.out sed 's/^X//' >concordance.out << 'END-of-concordance.out' Xit: 2 1 Xwas: 2 1 Xthe: 2 1 Xbest: 1 Xof: 2 1 Xtimes: 2 1 Xworst: 2 END-of-concordance.out echo x - dijkstra.out sed 's/^X//' >dijkstra.out << 'END-of-dijkstra.out' Xpensacola : 19 Xpittsburg : 15 Xpeoria : 10 Xpueblo : 9 Xphoenix : 6 Xpendleton : 2 Xpierre : 0 END-of-dijkstra.out echo x - game.out sed 's/^X//' >game.out << 'END-of-game.out' Xlet's play guess the animal. XI know. Is it a cat ? Xwhat is your animal? Xwhat is a yes/no question that I can use to tell a cat from a dog ? Xfor a dog is the answer yes or no? XTry again? Xdoes it bark? XI know. Is it a cat ? Xwhat is your animal? Xwhat is a yes/no question that I can use to tell a cat from a fish ? Xfor a fish is the answer yes or no? XTry again? END-of-game.out echo x - letterfreq.out sed 's/^X//' >letterfreq.out << 'END-of-letterfreq.out' Xletter a occurrences 26 Xletter b occurrences 5 Xletter c occurrences 58 Xletter d occurrences 27 Xletter e occurrences 70 Xletter f occurrences 5 Xletter g occurrences 5 Xletter h occurrences 16 Xletter i occurrences 37 Xletter j occurrences 0 Xletter k occurrences 1 Xletter l occurrences 18 Xletter m occurrences 6 Xletter n occurrences 48 Xletter o occurrences 50 Xletter p occurrences 13 Xletter q occurrences 0 Xletter r occurrences 57 Xletter s occurrences 32 Xletter t occurrences 59 Xletter u occurrences 34 Xletter v occurrences 7 Xletter w occurrences 12 Xletter x occurrences 6 Xletter y occurrences 3 Xletter z occurrences 7 END-of-letterfreq.out echo x - parse.out sed 's/^X//' >parse.out << 'END-of-parse.out' Xidentifier a Xidentifier b Xidentifier c X times node X plus node END-of-parse.out echo x - poly.out sed 's/^X//' >poly.out << 'END-of-poly.out' X2 X^2 + 3 X + 5 X4 X + 3 X8 X^3 + 18 X^2 + 29 X + 15 X2 X^2 + 3 X + 5 X4 X + 3 END-of-poly.out echo x - sieve.out sed 's/^X//' >sieve.out << 'END-of-sieve.out' X0,1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97, END-of-sieve.out echo x - traversal.out sed 's/^X//' >traversal.out << 'END-of-traversal.out' XPre order traversal XABDECFG XIn order traversal XDBEAFCG XPost order traversal XDEBFGCA XLevel order traversal XABCDEFG END-of-traversal.out echo x - wordlengthfreq.out sed 's/^X//' >wordlengthfreq.out << 'END-of-wordlengthfreq.out' Xword size 0 count 0 Xword size 1 count 22 Xword size 2 count 22 Xword size 3 count 10 Xword size 4 count 14 Xword size 5 count 16 Xword size 6 count 6 Xword size 7 count 7 Xword size 8 count 5 Xword size 9 count 3 Xword size 10 count 3 Xword size 11 count 5 Xword size 12 count 1 Xword size 13 count 0 Xword size 14 count 1 Xword size 15 count 0 Xword size 16 count 1 Xword size 17 count 0 Xword size 18 count 1 Xword size 19 count 0 Xbig words 2 END-of-wordlengthfreq.out exit