/*------------------------------------------------* | File: btree.c - Binary tree routines for sort. | | v1.00 MLO 911226 - see the comments in sort.c | *------------------------------------------------*/ #include #include #include #include "mlo.h" #include "sort.h" extern short int abortProg; extern Boolean reverse; extern FILE *fp; extern Node *root; #ifndef SIMPLE extern char *temp1; #endif #ifdef BALANCED_TREE extern Node *critical, *father; static short int sign(int x); #endif void FreeTree( Node *pN ){ /** | Frees (recursively) the binary tree, at node pointed to by pN. **/ if (pN->left != NULL) FreeTree(pN->left); if (pN->right != NULL) FreeTree(pN->right); free(pN); } Node *InsertTree( char *buffer, Node *pN ){ /** | Inserts (recursively) the string "buffer" in the binary tree; see | the comments in sort.c about the balanced binary tree algorithm. **/ #ifdef BALANCED_TREE if (pN != NULL) { /** | This node is not empty; compare our string with the one | related to this node, and follow right or left branch - | or bump the node counter if the strings are identical (if | so, the tree is already balanced since no new nodes has been | created; if not, alter the balance count in this node toward | right or left). For the balancing algorithm, we need to know | the last node having a non-zero balance factor, and his father. **/ short int z; if ((z = Compare(buffer, pN->line)) == 0) { (pN->count)++; critical = NULL; } else { if (pN->balance) critical = pN; if (z < 0) { if (pN->left != NULL && pN->left->balance) father = pN; pN->left = InsertTree(buffer, pN->left); } else { if (pN->right != NULL && pN->right->balance) father = pN; pN->right = InsertTree(buffer, pN->right); } } } else { /** | We are at the end of the binary tree; a new node | must be inserted here. **/ if ((pN = malloc(sizeof(Node)+strlen(buffer))) == NULL) { puts("sort: couldn't obtain heap memory."); FreeTree(root); if (temp1 != NULL) free(temp1); if (fp != NULL) fclose(fp); exit(SYS_ABORT_CODE); } strcpy(pN->line, buffer); pN->balance = 0; pN->count = 1; pN->left = NULL; pN->right = NULL; } return pN; #else /** | Unbalanced binary tree algorithm. **/ if (pN != NULL) { short int z; #ifdef SIMPLE if ((z = strcmp(buffer, pN->line)) == 0) { #else if ((z = Compare(buffer, pN->line)) == 0) { #endif (pN->count)++; } else if (z < 0) { pN->left = InsertTree(buffer, pN->left); } else { pN->right = InsertTree(buffer, pN->right); } } else { if ((pN = malloc(sizeof(Node)+strlen(buffer))) == NULL) { puts("sort: couldn't obtain heap memory."); FreeTree(root); #ifndef SIMPLE if (temp1 != NULL) free(temp1); #endif if (fp != NULL) fclose(fp); exit(SYS_ABORT_CODE); } strcpy(pN->line, buffer); pN->count = 1; pN->left = NULL; pN->right = NULL; } return pN; #endif } void PrintTree( Node *pN ){ /** | Prints (recursively) the binary tree, at node pointed to by pN. | The allocated memory is also freed. **/ if (reverse) { if (pN->right != NULL) PrintTree(pN->right); } else { if (pN->left != NULL) PrintTree(pN->left); } if (!abortProg) { while ((pN->count)--) fputs(pN->line, stdout); CheckBreak(False); } if (reverse) { if (pN->left != NULL) PrintTree(pN->left); } else { if (pN->right != NULL) PrintTree(pN->right); } free(pN); } #ifdef BALANCED_TREE void BalanceTree( char *key ) { /** | If the binary tree needs re-balancing (critical != NULL), | we rearrange the node ordering so that the number of them | being in the right sub-tree and in the left sub-tree in | EVERY node differs at most by one. To obtain this, is | sufficient to start from *critical. **/ short int a, a0; Node *p = critical; Node *p0; if (critical == NULL) return; if ((a0 = Compare(key, p->line)) != 0) { a0 = sign(a0); p = p0 = (a0 > 0) ? p->right : p->left; while ((a = Compare(key, p->line)) != 0) { p->balance = (a = sign(a)); p = (a > 0) ? p->right : p->left; } } if (a0 && critical->balance == a0) { if (p0->balance == a0) { p = p0; if (a0 > 0) { critical->right = p0->left; p0->left = critical; } else { critical->left = p0->right; p0->right = critical; } critical->balance = p0->balance = 0; } else if (p0->balance == -a0) { if (a0 > 0) { p = p0->left; p0->left = p->right; p->right = p0; critical->right = p->left; p->left = critical; } else { p = p0->right; p0->right = p->left; p->left = p0; critical->left = p->right; p->right = critical; } if (p->balance == 0) { critical->balance = p0->balance = 0; } else if (p->balance == a0) { critical->balance = -a0; p0->balance = 0; } else if (p->balance == -a0) { critical->balance = 0; p0->balance = a0; } p->balance = 0; } if (father == NULL) { root = p; } else if (critical == father->right) { father->right = p; } else { father->left = p; } } else { critical->balance += a0; } } static short int sign( int x ){ /** | "sign" function **/ if (x > 0) return 1; else if (x < 0) return -1; else return 0; } #endif