/*++++++++++++++ .IDENTIFICATION tree3.c .LANGUAGE C .AUTHOR Francois Ochsenbein [CDS] .ENVIRONMENT Btrees .KEYWORDS CDS Catalogue Server .VERSION 1.0 07-Dec-2002: Tests for B-tree .COMMENTS 3 nodes: lt eq gt ---------------*/ #include #include /* Malloc */ #include #include #include #define ITEMS(a) (sizeof(a)/sizeof(a[0])) #define MIN(a,b) ((a)<(b) ? (a) : (b)) #define MAX(a,b) ((a)>(b) ? (a) : (b)) typedef int RECORD; /* Linked records, to sort them... */ typedef struct linked_RECORD { struct linked_RECORD *lt ; struct linked_RECORD *eq ; struct linked_RECORD *gt ; RECORD rec ; } LRECORD ; static int compare_calls; static int tree_depth; static int mrec = 20 ; static int irec, truncated ; static LRECORD *last, *arec, *root; /* Definitions related to Center of Field */ static int (*digest_routine)() ; /* Other options */ static int opted = 'o'; /* 'o' ==> all */ /*================================================================== Comparison routines *==================================================================*/ static int compare(RECORD *a, RECORD *b) /*++++++++++++++++ .PURPOSE Compare two records according to the sort options .RETURNS Difference (a-b) -----------------*/ { compare_calls++; return(*a - *b); } static void print_nodes(LRECORD *node) /*++++++++++++++++ .PURPOSE Print all nodes in order .RETURNS --- .REMARKS Recursivity = simplicity !! -----------------*/ { static int depth = 0; LRECORD *n; if (node->lt) depth++, print_nodes(node->lt), depth--; for (n=node; n; n=n->eq) printf("%10d:%-5d", n->rec, depth); if (node->gt) depth++, print_nodes(node->gt), depth--; /* if (depth==0) putchar('\n'); */ } /*================================================================== Sorting the Records *==================================================================*/ static int add_rec(RECORD *new) /*++++++++++++++++ .PURPOSE Add a new record, link it. .RETURNS 0 (not kept) / 1 -----------------*/ { LRECORD *node, *prev, *prev1, *n; int diff, comp1, depth; comp1 = compare_calls; /* (0) Check if the new record has any use... */ n = (LRECORD *)0; /* n -> last */ if (irec == mrec) { if (!last) for (last=root; last->gt; last=last->gt) n = last; diff = compare(new, &(last->rec)); if (diff >= 0) { truncated++; return(0); } } /* (1) Find where in the list we've to insert the new record */ node = root; prev = prev1 = (LRECORD *)0; depth = 0; while(node) { diff = compare(new, &(node->rec)); prev1 = prev; prev = node; if (diff == 0) break; node = diff < 0 ? node->lt : node->gt ; depth++; } if (depth > tree_depth) tree_depth = depth; /* (2) If max attained, put the new in place of last */ if (irec == mrec) { if(opted=='o') { printf(" new=%d\n", *new); print_nodes(root); putchar('\n'); } truncated++ ; node = last ; /* Where to store new record */ if (last->eq) { /* Several last records... */ node = last->eq; last->eq = node->eq ; } else { /* Set n->gt gives last */ if (!n) for (last=root; last->gt; last=last->gt) n = last; if (!n) { /* Happens when root == last ! */ root = root->lt; last = root; } else { last = n; last->gt = node->lt; } } while(last->gt) last = last->gt; } else node = arec + irec++ ; /* (3) Insert the new record, and set the links */ *(&(node->rec)) = *new ; node->lt = node->gt = node->eq = (LRECORD *)0; if (!prev) root = node; else { if (diff < 0) prev->lt = node; else if (diff > 0) { /* I may have changed the last */ prev->gt = node; if (last) while(last->gt) last = last->gt; } else { node->eq = prev->eq; prev->eq = node; } } #if 1 printf("\n....Added#%d = %d: comparisons=%d ", irec, *new, compare_calls-comp1); putchar('\n'); print_nodes(root); putchar('\n'); #endif return(1) ; } /*================================================================== Main Program *==================================================================*/ main (argc, argv) int argc; char **argv; { RECORD rec; int n; arec = (LRECORD *)malloc(mrec*sizeof(LRECORD)); while (1) { printf("....Random list: "); n = getchar(); if (n<0) break; irec = 0; compare_calls = 0; root = last = (LRECORD *)0; tree_depth = 0; for (n=0; n<100; n++){ rec = rand()%100; add_rec(&rec); } printf("%d total comparisons, depth=%d", compare_calls, tree_depth); n = getchar(); print_nodes(root); putchar('\n'); } /* Generate one up, one down, random */ irec = 0; compare_calls = 0; root = last = (LRECORD *)0; tree_depth = 0; printf("----Adding ascending list: "); n = getchar(); for (n=0; n<1000; n++){ rec = n; add_rec(&rec); } printf("%d total comparisons, depth=%d", compare_calls, tree_depth); n = getchar(); print_nodes(root); putchar('\n'); irec = 0; compare_calls = 0; root = last = (LRECORD *)0; tree_depth = 0; printf("----Adding descending list: "); n = getchar(); for (n=30; --n>=0 ;){ rec = n; add_rec(&rec); } printf("%d total comparisons, depth=%d", compare_calls, tree_depth); n = getchar(); print_nodes(root); putchar('\n'); exit(0); }