/* * qdriver.c * Reads in a data file consisting of lines of text of the form * X9Message * where X = A for add to queue, D=delete, P=print the queue * 9 = pripority of the queued item * Message = string to enqueue * Note: actions D and P have no priority or message/ * As each action is performed, a status message is printed. * * Must be linked with object files from qapp.c and llgen.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "llgen.h" #include "qapp.h" int dequeue( struct List *, struct List *, void * ); int enqueue( struct List *, struct List *, void * ); #define QMAX 100 /* maximum number of elements in a queue */ int main( int argc, char *argv[] ) { char record[64]; /* the raw word from the file */ int count; void * temp; /* temporary data area */ struct List *queue, *free_list; /* our two queues */ FILE *fin; if (argc!=2) { fprintf( stderr, "Error! Usage: qdriver 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 for queue */ queue = CreateLList( CreateData1, DeleteData1, DuplicatedNode1, NodeDataCmp1); free_list = CreateLList( CreateData2, DeleteData2, DuplicatedNode2, NodeDataCmp2); if ( queue==NULL || free_list==NULL ) { fprintf( stderr, "Error creating queue/n" ); exit( EXIT_FAILURE ); } /* allocate the free list */ for (count=0; count<QMAX; count++) { if (!AddNodeAtHead(free_list, record)) { fprintf( stderr, "Could not create queue of %d/n", QMAX ); exit(EXIT_FAILURE); } } /* begin processing file */ temp = CreateData2(NULL); if (temp==NULL) { fprintf(stderr, "Error creating temporary data area/n" ); exit( EXIT_FAILURE ); } while ( fgets(record, 64, fin)!=NULL ) { if (strlen(record)>0) record[strlen(record)-1]=0; /* strip CR/LF */ if (*record=='A') /* add */ { ((pND2)temp)->priority = *(record+1) - '0'; ((pND2)temp)->text = record+2; if (enqueue(queue, free_list, temp)==0) { fprintf(stderr, "Error enqueueing %d %s/n", ((pND2)temp)->priority, ((pND2)temp)->text); exit(EXIT_FAILURE); } else{ printf("Enqueued %d %s/n", ((pND2)temp)->priority, ((pND2)temp)->text); if (queue->LCount==0) printf("Empty queue/n"); else{ Link curr; printf("-------- List so far --------/n"); for ( curr=queue->LHead; curr!=NULL; curr=curr->next) printf("%d %s/n", ((pND2)curr->pdata)->priority, ((pND2)curr->pdata)->text); } } } else if( *record=='D' ) /* delete */ { if (dequeue(queue, free_list, temp)==0) { fprintf(stderr, "Error dequeueing %d %s/n", ((pND2)temp)->priority, ((pND2)temp)->text); exit(EXIT_FAILURE); } else printf( "Dequeued %d %s/n", ((pND2)temp)->priority, ((pND2)temp)->text); } else if( *record=='P' ) /*print */ { if (queue->LCount==0) printf( "Empty queue/n" ); else { Link curr; printf("-------- List so far --------/n"); for ( curr=queue->LHead; curr!=NULL; curr=curr->next) printf("%d %s/n", ((pND2)curr->pdata)->priority, ((pND2)curr->pdata)->text); } } else fprintf( stderr, "Data error: %s/n", record ); } fclose(fin); return EXIT_SUCCESS; } /* * enqueue loads the data items in entry into the head node of * the free list, then adds that node to the queue based on * priority */ int enqueue( struct List * lqueue, struct List * lfree, void * new_entry ) { Link curr, new_node; /* Are there any free nodes left */ if (lfree->LCount==0) { fprintf( stderr, "Exceeded maximum queue size/n" ); return 0; } /* load the data into the head of the free list */ new_node = lfree->LHead; if (DataCopy(new_node->pdata, new_entry)==0) return 0; /* adding to an empty list? */ if (lqueue->LCount==0) { lfree->LHead = lfree->LHead->next; new_node->prev = NULL; new_node->next = NULL; lqueue->LTail = new_node; lqueue->LHead = new_node; lqueue->LCount = 1; lfree->LCount -= 1; return 1; }else{ /* Traverse the list to find the insertion position */ for ( curr=lqueue->LHead; ; curr=curr->next) { if (curr==NULL||NodeDataCmp1(new_entry, curr->pdata)<0) { lfree->LHead = lfree->LHead->next; if (curr==NULL) /* if end of list */ { new_node->prev = lqueue->LTail; new_node->next = NULL; new_node->prev->next = new_node; lqueue->LTail = new_node; }else{ if(curr->prev==NULL) /* adding at head ? */ lqueue->LHead = new_node; new_node->prev = curr->prev; new_node->next = curr; if (curr->prev!=NULL) curr->prev->next = new_node; curr->prev = new_node; } lqueue->LCount += 1; /* update the free list */ lfree->LCount -= 1; return 1; }else{ pND2 p1, p2; p1 = curr->pdata; p2 = new_entry; printf( "searched at %d %s to insert %d %s/n", p1->priority, p1->text, p2->priority, p2->text); } } } } /* * dequeue takes a pointer that will be set to the data in the * node at the head of the queue. It then moves the node being * dequeued from the queue to the free list. Note that if you do * not use the dequeued data before next queue operation, the * data is lost, so copy it if you need to. Return 0 on error. */ int dequeue( struct List * lqueue, struct List * lfree, void * our_data) { Link dequeued_link; /* is there anything to dequeue? */ if (lqueue->LCount==0) { fprintf( stderr, "Error dequeue from empty queue/n" ); return 0; } /* make a copy of the data being dequeued */ if (DataCopy(our_data, lqueue->LHead->pdata)==0) return 0; /* remove the node from the queue */ dequeued_link = lqueue->LHead; lqueue->LHead = lqueue->LHead->next; lqueue->LHead->prev = NULL; /* can move this statement, because the queue just don't need to know the previous pointer */ lqueue->LCount -= 1; /* add the node to the free list */ dequeued_link->prev=NULL; dequeued_link->next = lfree->LHead; lfree->LHead->prev = dequeued_link; /* you can move this statement, because the queue just don't need to know the previous pointer */ lfree->LHead = dequeued_link; lfree->LCount += 1; return 1; } /* 阅读后注释: * 1.本主函数通过使用两个双向链表定义实现队列的空闲链方案。 * 由于队列中不需要得到前指针,因此我们可以看到在入列中并不需要维护前指针,但是 * 为了完整这里还是增加了那两条修改prev指针的语句,以使得队列是一个完整的双向链 * 2.注释这里空闲链结点是返回的,但是其text内容在每次返还时会delete,即空闲链仅 * 维护结点,而不维护结点中的数据 */ /* * qapp.h * Application-specific data items fro linked-list queues. */ #ifndef QAPP_H #define QAPP_H /* * Our first list's nodes consist of a pointer to * text and a priority level. */ #define TEXT_SIZE 60 /* the maximum size of our text string */ extern int DataCopy( void *, void * ); /* * The data and functions for the queue */ struct NodeData1{ char *text; unsigned int priority; }; typedef struct NodeData1 * pND1; extern void * CreateData1( void * ); extern int DeleteData1( void * ); extern int DuplicatedNode1( Link, Link ); extern int NodeDataCmp1( void *, void* ); /* * The free list has identical nodes */ struct NodeData2{ char *text; unsigned int priority; }; typedef struct NodeData2 * pND2; extern void * CreateData2( void * ); extern int DeleteData2( void * ); extern int DuplicatedNode2( Link, Link ); extern int NodeDataCmp2(void*, void*); #endif /* * 阅读后注释 * 队列相对于栈会复杂一点,就在于它的插入和移出的方向不一致。 * 包含如下主要问题: * 1. 内存表示问题。对于数组,可以使用循环缓冲区解决,这在清华出版社的黄色封面的 * 数据结构C++描述过。对于链表,可以尾插入,头删除,但是这样会导致内存碎片化,因此 * 使用一个内存缓冲池,或是使用一个空闲链表 * 2. 空闲链的数据成员与结点的数据成员一致,但是操作不同 */ /* * qapp.c * Application-specific function fro queue examples * Replace these routines with your own. */ #include <stdio.h> #include <stdlib.h> /* for free() */ #include <string.h> /* fro strcmp() and strdup() */ #include "llgen.h" #include "qapp.h" /* linked-list function for queue */ /* * our nodes come from the free list, * so this function is never called. */ void * CreateData1(void *data) { return NULL; } int DeleteData1(void *data) { /* * In this case, NodeData1 consists of a pointer and int. * The integer will be returned to memory when the node * is freed. However, the string must be freed manually. */ free( ((pND1)data)->text ); 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 ) { return 2; } /* compare only the priority of the queue data */ int NodeDataCmp1( void *first, void *second ) { return ( ((pND1)first)->priority-((pND1)second)->priority); } /* Now the functions for the list of free nodes */ /* data is a priority level (int) and text(string) */ void * CreateData2(void *data) // here data is dummy, unused! { struct NodeData1 * new_data; /* allocate our data structure */ new_data = malloc( sizeof(struct NodeData1) ); if (new_data==NULL) return NULL; /* move the values into the data structure */ /* * we assign a priority f 0 * and allocate a string of TEXT_SIZE+1 */ new_data->priority = 0; new_data->text = (char*)malloc(TEXT_SIZE+1); if ( new_data->text==NULL ) /* error copying string */ { free( new_data ); return NULL; } else return new_data; /* return a complete structure */ } int DeleteData2( void * data ) { /* * In this case, NodeData2 consists of a pointer. * The string must be freed manually. */ free( ((pND2)data)->text ); return 1; } /* this list inserts duplicated nodes */ int DuplicatedNode2( Link new_node, Link list_node ) { return 2; } /* this function is never called */ int NodeDataCmp2(void* first, void* second) { return 0; } /* function to copy our data */ int DataCopy( void * dest, void * src) { pND2 s, d; s = src; d = dest; if ( dest==NULL || src==NULL ) return 0; printf( "About to copy %d - %s /n", s->priority, s->text ); d->priority = s->priority; strncpy( d->text, s->text, TEXT_SIZE ); return 1; }