*-------------------------------------------------------------*/ #ifndef LLGEN_H /* make sure it's included only once */ #define LLGEN_H 1 struct Node { struct Node *prev; /* link to previous node */ struct Node *next; /* link to next node */ void *pdata; /* generic pointer to data */ }; typedef struct Node *Link; /* a linked list data structure */ struct List { Link LHead; Link LTail; unsigned int LCount; void * ( * LCreateData ) ( void * ); int ( * LDeleteData ) ( void * ); int ( * LDuplicatedNode ) ( Link, Link ); int ( * LNodeDataCmp ) ( void *, void * ); }; /* The four functions specific to an individual linked list are: LCreateData: is passed a pointer to an application-defined object and is expected to return a pointer to whatever is to be stored in the linked list. LDeleteData: is passed a pointer to the object an application has stored in a linked list. LDeleteData must destroy the object. LDuplicatedNode: is passed two pointers. The first pointer is to a node that you would like to add to a linked list and the second is to a node that is already in the list but is a duplicate of the first pointer. LDuplicatedNode returns: 0 -> do nothing to list 1 -> destroy duplicate 2 -> add duplicate to list LNodeDataCmp: is passed pointers to two application data objects and must compare them, returning a number that is < 0, zero, or > 0, depending on the relationship between the first and second objects. */ /*--- generic linked-list primitives ---*/ int AddNodeAscend ( struct List *, void * ); int AddNodeAtHead ( struct List *, void * ); struct List * CreateLList ( void * ( * ) ( void * ), /* create data */ int ( * ) ( void * ), /* delete data */ int ( * ) ( Link, Link ), /* duplicate */ int ( * ) ( void *, void * )); /* compare */ Link CreateNode ( struct List * , void * ); int DeleteNode ( struct List *, Link ); Link FindNode ( struct List *, void * ); Link FindNodeAscend ( struct List *, void * ); Link GotoNext ( struct List *, Link ); Link GotoPrev ( struct List *, Link ); #endif /*--- llgen.c ------------------------------ Listing 2-3 -------- * Generic primitive functions for doubly linked lists. * Contains no application-specific functions. * Functions are in alphabetical order. *------------------------------------------------------------*/ #include <stdlib.h> #include <string.h> #define IN_LL_LIB 1 /* in the library of primitives */ #include "llgen.h" /*--- Aliases to make the code more readable ---*/ #define LLHead (L->LHead) /* The head of the current list */ #define LLTail (L->LTail) /* The tail of the current list */ #define NodeCount (L->LCount) /* Nodes in the current list */ #define CreateData (*(L->LCreateData)) #define DeleteData (*(L->LDeleteData)) #define DuplicatedNode (*(L->LDuplicatedNode)) #define NodeDataCmp (*(L->LNodeDataCmp)) /*---------------------------------------------------- * Add a node at head: first allocate the space for * the data, then allocate a node with a pointer to * the data, then add the node to the list. *--------------------------------------------------*/ int AddNodeAtHead ( struct List *L, void *nd ) { Link pn; pn = CreateNode ( L, nd ); if ( pn == NULL ) return ( 0 ); /*--- Add the node ---*/ if ( LLHead == NULL ) /* is it the first node? */ { LLHead = LLTail = pn; /*--- yes ---*/ } else /*--- no ---*/ { LLHead->prev = pn; /* first goes node before Head */ pn->next = LLHead; /* put Head next */ LLHead = pn; /* then point Head to us */ } NodeCount += 1; return ( 1 ); } /*---------------------------------------------------- * Add ascending. Adds a node to an ordered list. *--------------------------------------------------*/ int AddNodeAscend ( struct List *L, void *nd ) { Link pn; /* to node we're creating */ Link prev, curr; /* our current search */ struct Node dummy; /* a dummy node */ int compare; pn = CreateNode ( L, nd ); if ( pn == NULL ) return ( 0 ); /* attach dummy node to head of list */ dummy.next = LLHead; dummy.prev = NULL; if ( dummy.next != NULL ) dummy.next->prev = &dummy; prev = &dummy; curr = dummy.next; for ( ; curr != NULL; prev = curr, curr = curr->next ) { compare = NodeDataCmp ( pn->pdata, curr->pdata ); if ( compare <= 0 ) break; /* new node equals or precedes curr */ } if ( curr != NULL && compare == 0 ) { compare = DuplicatedNode ( pn, curr ); if ( compare == 2 ) /* do nothing -- will get inserted */; else { /* first, repair the linked list */ LLHead = dummy.next; LLHead->prev = NULL; /* delete the duplicated node, if appropriate */ if ( compare == 1 ) { DeleteData( pn->pdata ); free ( pn ); } return ( 1 ); } } prev->next = pn; pn->prev = prev; pn->next = curr; if ( curr != NULL ) curr->prev = pn; else LLTail = pn; /* this node is the new tail */ NodeCount += 1; /* now, unhook the dummy head node */ LLHead = dummy.next; LLHead->prev = NULL; return ( 1 ); } /*--------------------------------------------------------------- * Creates a linked-list structure and returns a pointer to it. * On error, returns NULL. This functions accepts pointers * to the four list-specific functions and initializes the * linked-list structure with them. *-------------------------------------------------------------*/ struct List * CreateLList ( void * ( * fCreateData ) ( void * ), int ( * fDeleteData ) ( void * ), int ( * fDuplicatedNode ) ( Link, Link ), int ( * fNodeDataCmp ) ( void *, void * )) { struct List * pL; pL = (struct List *) malloc ( sizeof ( struct List )); if ( pL == NULL ) return NULL; pL->LHead = NULL; pL->LTail = NULL; pL->LCount = 0; pL->LCreateData = fCreateData; pL->LDeleteData = fDeleteData; pL->LDuplicatedNode = fDuplicatedNode; pL->LNodeDataCmp = fNodeDataCmp; return ( pL ); } /*--------------------------------------------------------------- * Creates a node and then calls the application-specific * function CreateData() to create the node's data structure. * Returns NULL on error. *-------------------------------------------------------------*/ Link CreateNode ( struct List *L, void *data ) { Link new_node; new_node = (Link) malloc ( sizeof ( struct Node )); if ( new_node == NULL ) return ( NULL ); new_node->prev = NULL; new_node->next = NULL; /*--- now call the application-specific data allocation ---*/ new_node->pdata = CreateData( data ); if ( new_node->pdata == NULL ) { free ( new_node ); return ( NULL ); } else return ( new_node ); } /*--------------------------------------------------------------- * Deletes the node pointed to by to_delete. * Function calls list-specific function to delete data. *-------------------------------------------------------------*/ int DeleteNode ( struct List *L, Link to_delete ) { Link pn; if ( to_delete == NULL ) /* Double check before */ return ( 0 ); /* deleting anything. */ if ( to_delete->prev == NULL ) /* we're at the head */ { LLHead = to_delete->next; /* update head */ LLHead->prev = NULL; /* update next node */ } else if ( to_delete->next == NULL ) { /* we're at the tail */ pn = to_delete->prev; /* get the previous node */ pn->next = NULL; LLTail = pn; /* update tail */ } else /* we're in the list */ { pn = to_delete->prev; /* get the previous node */ pn->next = to_delete->next; /* update previous node to */ /* point to the next one. */ pn = to_delete->next; /* get the next node */ pn->prev = to_delete->prev; /* update it to point to */ /* the previous one. */ } DeleteData ( to_delete->pdata ); /* delete the data */ free ( to_delete ); /* free the node */ NodeCount -= 1; return ( 1 ); } /*--------------------------------------------------------------- * Finds node by starting at the head of the list, stepping * through each node, and comparing data items with the search * key. The Ascend version checks that the data in the node * being examined is not larger than the search key. If it is, * we know the key is not in the list. Returns pointer to node * on success or NULL on failure. *-------------------------------------------------------------*/ Link FindNode ( struct List *L, void *nd ) { Link pcurr; /* the node we're examining */ if ( LLHead == NULL ) /* empty list */ return ( NULL ); for ( pcurr = LLHead; pcurr != NULL; pcurr = pcurr->next) { if ( NodeDataCmp ( nd, pcurr->pdata ) == 0 ) return ( pcurr ); } return ( NULL ); /* could not find node */ } Link FindNodeAscend ( struct List *L, void *nd ) { Link pcurr; /* the node we're examining */ int cmp_result; if ( LLHead == NULL ) /* empty list */ return ( NULL ); for ( pcurr = LLHead; pcurr != NULL; pcurr = pcurr->next) { cmp_result = NodeDataCmp ( nd, pcurr->pdata ); if ( cmp_result < 0 ) return ( NULL ); /* too far */ if ( cmp_result == 0 ) /* just right */ return ( pcurr ); } return ( NULL ); /* could not find node */ } /*--------------------------------------------------------------- * The Goto functions return the pointer to the requested node * or NULL on error. *-------------------------------------------------------------*/ Link GotoNext ( struct List *L, Link pcurr ) { if ( pcurr->next == NULL || pcurr == LLTail ) return ( NULL ); else return ( pcurr->next ); } Link GotoPrev ( struct List *L, Link pcurr ) { if ( pcurr->prev == NULL || pcurr == LLHead ) return ( NULL ); else return ( pcurr->prev ); } /*--- llapp.h ----------------------------- Listing 2-4a ------- * Application-specific data for linked list in lldriver.c (2-5) * Used in conjunction with llapp.c (Listing 2-4b). *-------------------------------------------------------------*/ #ifndef LLAPP_H #define LLAPP_H 1 /* * Our first list's nodes consist of a pointer to * a word and a count of occurrences. */ struct NodeData1 { char *word; unsigned int u; }; typedef struct NodeData1 * pND1; extern void * CreateData1 ( void * ); extern int DeleteData1 ( void * ); extern int DuplicatedNode1 ( Link, Link ); extern int NodeDataCmp1 ( void *, void * ); /* * Our second list's nodes consist of a * pointer to a word. */ struct NodeData2 { char *word; }; typedef struct NodeData2 * pND2; extern void * CreateData2 ( void * ); extern int DeleteData2 ( void * ); extern int DuplicatedNode2 ( Link, Link ); extern int NodeDataCmp2 ( void *, void * ); #endif /*--- llapp.c ----------------------------- Listing 2-4b -------- * Application-specific functions for linked-list examples. * Replace these routines with your own. *-------------------------------------------------------------*/ #include <stdlib.h> /* for free() */ #include <string.h> /* for strcmp() and strdup() */ #include "llgen.h" #include "llapp.h" /* data is a pointer to a string */ void * CreateData1 ( void * data ) { struct NodeData1 * new_data; /*--- allocate our data structure ---*/ if ((new_data = malloc ( sizeof ( struct NodeData1 ))) == NULL) return ( NULL ); /*--- move the values into the data structure ---*/ new_data->u = 1; new_data->word = strdup ( (char *) data ); if ( new_data->word == NULL ) /* error copying string */ { free ( new_data ); return ( NULL ); } else return ( new_data ); /* return a complete structure */ } int DeleteData1 ( void * data ) { /* * In this case, NodeData1 consists of: a pointer and an int. * The integer will be returned to memory when the node * is freed. However, the string must be freed manually. */ free ( ((pND1) data)->word ); return ( 1 ); } /*--------------------------------------------------------------- * This function determines what to do when inserting a node * into a list if an existing node with the same data is found * in the list. In this case, since we are counting words, if a * duplicate word is found, we simply increment the counter. * * Note this function should return one of the following values: * 0 an error occurred * 1 delete the duplicate node * 2 insert the duplicate node * Any other processing on the duplicate should be done in this * function. *-------------------------------------------------------------*/ int DuplicatedNode1 ( Link new_node, Link list_node ) { /* adding an occurrence to an existing word */ pND1 pnd = list_node->pdata; pnd->u += 1; return ( 1 ); } int NodeDataCmp1 ( void *first, void *second ) { return ( strcmp ( ((pND1) first)->word, ((pND1) second)->word )); } /*=== Now the functions for the second linked list ===*/ void * CreateData2 ( void * data ) { struct NodeData2 * new_data; /*--- allocate the data structure ---*/ if ((new_data = malloc ( sizeof ( struct NodeData2 ))) == NULL) return ( NULL ); /*--- move the values into the data structure ---*/ new_data->word = strdup ( (char *) data ); if ( new_data->word == NULL ) /* error copying string */ { free ( new_data ); return ( NULL ); } else return ( new_data ); } int DeleteData2 ( void * data ) { /* * In this case, NodeData2 consists of a pointer. * The string must be freed manually. */ free ( ((pND2) data)->word ); return ( 1 ); } /* this list inserts duplicated nodes */ int DuplicatedNode2 ( Link new_node, Link list_node ) { return ( 2 ); } int NodeDataCmp2 ( void *first, void *second ) { return ( strcmp ( ((pND2) first)->word, ((pND2) second)->word )); } /*--- lldriver.c -------------------------- Listing 2-5 ------- * Reads in text words from the file specified on the command * line and places them into two linked lists. Then exercises * a variety of linked-list activities, printing the results * at every step. * Must be linked to linked-list primitives in Listings 2-2 * through 2-4b. *-------------------------------------------------------------*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "llgen.h" /* Header for generic linked lists */ #include "llapp.h" /* Header for appl.'s linked lists */ int main ( int argc, char *argv[] ) { char word[64]; /* the raw word from the file */ int count; struct List *L1, *L2; /* two different linked lists */ Link w1, w2, w3; /* cursors used to walk lists */ FILE *fin; /* the input file */ if ( argc != 2 ) { fprintf ( stderr, "Error! Usage: lldriver filename\n" ); exit ( EXIT_FAILURE ); } fin = fopen ( argv[1], "rt" ); if ( fin == NULL ) { fprintf ( stderr, "Could not find/open %s\n", argv[1] ); exit ( EXIT_FAILURE ); } /*--- set up linked-list data structures ---*/ L1 = CreateLList ( CreateData1, /* in llapp.c */ DeleteData1, /* " */ DuplicatedNode1, /* " */ NodeDataCmp1 ); /* " */ L2 = CreateLList ( CreateData2, /* in llapp.c */ DeleteData2, /* " */ DuplicatedNode2, /* " */ NodeDataCmp2 ); /* " */ if ( L1 == NULL || L2 == NULL ) { fprintf ( stderr, "Error creating linked list\n" ); exit ( EXIT_FAILURE ); } /*--- begin processing file ---*/ while ( fgets ( word, 64, fin ) != NULL ) { if ( strlen ( word ) > 0 ) word[strlen ( word ) - 1] = 0; /* strip tail \n */ /* now, add the word to both lists */ if ( ! AddNodeAscend ( L1, word )) fprintf ( stderr, "Warning! Error while adding node to L1.\n" ); if ( ! AddNodeAtHead ( L2, word )) fprintf ( stderr, "Warning! Error while adding node to L2.\n" ); } fclose ( fin ); /* now, walk the lists */ printf( "L1 contains %u items:\n", L1->LCount ); for ( w1 = L1->LHead; w1 != NULL; w1 = w1->next ) printf(" %s occured %d times.\n", ((pND1) (w1->pdata))->word, ((pND1) (w1->pdata))->u ); printf( "L2 contains %u items:\n", L2->LCount ); for ( w1 = L2->LHead; w1 != NULL; w1 = w1->next ) printf ( " %s\n", ((pND2) (w1->pdata))->word ); /* both ways at once */ printf ( "L2 contains %u items:\n", L2->LCount ); w1 = L2->LHead; w2 = L2->LTail; for ( ; w1 != NULL && w2 != NULL; w1 = w1->next, w2 = w2->prev ) printf( " %30s %30s\n", ((pND2) (w1->pdata))->word, ((pND2) (w2->pdata))->word ); /* "Find" each node and delete every other one */ count = 0; w1 = L2->LHead; while ( w1 != NULL ) { w3 = FindNode ( L2, w1->pdata ); if ( w3 != 0 ) { printf ( "Found node %s", ((pND2) (w3->pdata))->word ); count += 1; w1 = w3->next; if ( count & 1 ) { DeleteNode ( L2, w3 ); printf ( " and deleted it." ); } printf( "\n" ); } else w1 = NULL; } printf ( "L2 contains %u items:\n", L2->LCount ); w1 = L2->LHead; w2 = L2->LTail; for ( ; w1 != NULL && w2 != NULL; w1 = w1->next, w2 = w2->prev ) printf ( " %30s %30s\n", ((pND2) (w1->pdata))->word, ((pND2) (w2->pdata))->word ); return ( EXIT_SUCCESS ); }
双向链表
最新推荐文章于 2018-10-10 16:59:00 发布