//----------------------------------------------------------------------------- // Copyright © 2003 - Philip Howard - All rights reserved // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. //----------------------------------------------------------------------------- // package libh/avl // homepage http://libh.slashusr.org/ //----------------------------------------------------------------------------- // author Philip Howard // email libh at ipal dot org // homepage http://phil.ipal.org/ //----------------------------------------------------------------------------- // This file is best viewed using a fixed spaced font such as Courier // and in a display at least 120 columns wide. //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // program linefreq // // purpose Count the frequency of different line lines in the input. // // Demonstrate how single node can be defined to have 2 tree // links allowing each instance to be in 2 tree classes at // the same time. // // syntax linefreq ["sepchars"] < infile //----------------------------------------------------------------------------- #include #include #include #include #include #include #define LINESIZE 256 //----------------------------------------------------------------------------- // Define a struct that implements a link for a character string key. // Define a struct that implements a link for an unsigned long key. // Define a struct that implements a node to carry both links together. // Define a function that compares the character string keys in two links. // Define a function that compares the unsigned long keys in two links. //----------------------------------------------------------------------------- struct link_str { avl_link link ; char * key ; }; struct link_ul { avl_link link ; unsigned long key ; }; struct node { struct link_str line ; struct link_ul count ; char data [16] ; }; static int cmp_str( avl_link * arg_one, avl_link * arg_two, AVL * arg_tree ) { return strcmp( ((struct link_str *)arg_one)->key, ((struct link_str *)arg_two)->key ); } static int cmp_ul( avl_link * arg_one, avl_link * arg_two, AVL * arg_tree ) { return ( ((struct link_str *)arg_one)->key < ((struct link_str *)arg_two)->key ) ? -1 : ( ((struct link_str *)arg_one)->key > ((struct link_str *)arg_two)->key ) ? 1 : 0; } //----------------------------------------------------------------------------- // function main //----------------------------------------------------------------------------- int main ( int argc , char * * argv ) { AVL by_line ; AVL by_count ; struct link_str key_line ; struct node * node_p ; char line [ LINESIZE ]; //------------------------------ // Initialize both binary trees. //------------------------------ avl_init( & by_line, struct node, line, cmp_str ); avl_init( & by_count, struct node, count, cmp_ul ); //------------------------------------------------------------------- // Initialize a struct used as the lookup key with the array address. //------------------------------------------------------------------- key_line.key = line; //-------------------------------------------------------------- // Read every line from standard input to count them one by one. //-------------------------------------------------------------- while ( 0 <= get_line_file( line, LINESIZE, stdin ) ) { //------------------------------------------------------------ // If the node is found, increment the count for another word. // If not, create a new one with a count of 1 and insert it. //------------------------------------------------------------ if ( ( node_p = avl_find_exact( & by_line, & key_line ) ) ) { node_p->count.key ++; } else { if ( ! ( node_p = malloc( sizeof (struct node) - 16 + strlen( line ) + 1 ) ) ) { perror( "malloc" ); return 1; } node_p->count.key = 1; strcpy( ( node_p->line.key = node_p->data ), line ); avl_insert( & by_line, node_p ); } } //----------------------------------------------------------------------- // Step through all the lines in the "by line" tree and insert them into // the "by count" tree. Duplicates have to be allowed because many lines // may have the same count. //----------------------------------------------------------------------- avl_loop_forward( & by_line, node_p ) { avl_insert_dup( & by_count, node_p ); } //--------------------------------------------------------- // Print all the lines with count form the "by count" tree. //--------------------------------------------------------- avl_loop_reverse( & by_count, node_p ) { printf( "%11lu %s\n", node_p->count.key, node_p->line.key ); } return 0; }