#include <stdio.h> #include <stdlib.h> #include <string.h> /** data definitions **/ struct Node{ /* a node in our linked list */ char* City; int Temp; struct Node * Next; }; typedef struct Node* Link; /** Links are pointers to nodes */ Link Head; /* head of our lined list */ int NodeCount; /* how many nodes in the list */ /** function declarations for linked lists **/ int AddNodeAscend( Link ); /** add a node **/ int CreateLink( void ); /** initialize list **/ int DeleteNode( Link ); /** delete a node **/ int DuplicateNode( Link, Link ); /** handle duplicate inserts **/ void FreeNode( Link ); /** free a node's memory **/ void ShowNodes( void ); /** show list of nodes **/ int NodeCmp( Link, Link ); /** compare tow nodes **/ int AddNodeAscend( Link to_add ) { Link pn, /* local copy of node to be added */ prev, /* points to previouse node */ curr; /* points to node being examined */ struct Node dummy; int i; /** Make a copy of input **/ pn = ( Link ) malloc( sizeof( struct Node ) ); if ( pn==NULL ) return 0; memcpy(pn, to_add, sizeof( struct Node ) ); /** set up a dummy node to simplify logic **/ dummy.Next = Head; prev = &dummy; curr = Head; /* insert node pn */ for (;; prev=curr, curr=curr->Next) { if (curr==NULL) break; /* reached the end */ i = NodeCmp(pn, curr); if(i<=0) break; /* pn precedes curr */ } if( curr && i==0) /* we have a duplicate */ if( DuplicateNode( curr, pn )==0 ) return 1; /* bail out if DuplicateNode syas to */ prev->Next = pn; pn->Next = curr; NodeCount += 1; Head = dummy.Next; /* when insert a node , may be will change the head! for eample when the list is empty.*/ return 1; } /** Handle the duplicate node .In this program, we just delete the duplicate. **/ int DuplicateNode( Link inlist, Link duplicate ) { FreeNode(duplicate); return 0; } int DeleteNode( Link to_delete ) { Link curr, /* the current node */ prev; /* the previouse node */ int i; /** Is there anything in the list? **/ if (Head==NULL) return 0; /** If so , step through the list looking for the node **/ for (prev=NULL, curr=Head; curr!=NULL&&(i=NodeCmp(to_delete, curr))>0; prev=curr, curr=curr->Next) ; /* loop around */ /** Found a match , so delete it **/ if (curr!=NULL&&i==0) { if (prev) prev->Next = curr->Next; else /** deleting Head **/ Head = curr->Next; FreeNode(curr); NodeCount -= 1; return 1; } } int NodeCmp(Link a, Link b) { /** return 1, 0, -1, depending on whether the data in a is greater than, equal or less than b. **/ /** if temps are unequal, return based on temp **/ if ( a->Temp != b->Temp ) return ( a->Temp - b->Temp ); /** else, return based on city's name **/ return strcmp( a->City, b->City ); } void CreateList( void ) { Head = NULL; NodeCount = 0; } void FreeNode( Link n ) { free( n->City ); free( n ); } void ShowNodes( void ) { Link pn; int count, median; /** count the nodes **/ for (count=0, pn=Head; pn; pn=pn->Next) count+=1; /* compute the median node */ median = count/2+1; /* step through the list printing cities and * temperatures. Announce the median temperature. */ if(count) /* only print if there's a node */ { /* initialize the needed variables */ count = 0; /* count of nodes we've printed */ for ( pn=Head; pn; pn=pn->Next ) { printf("%-20s: %3d", pn->City, pn->Temp); count += 1; if ( count == median ) printf( " --Median-- "); printf("/n"); } } else printf( "Empty list/n"); } #define BUFFER_LEN 128 /** main line **/ int main( int argc, char *argv[]) { FILE *fin; /* file we'll be reading form */ char buffer[BUFFER_LEN]; /* where we'll read the file into */ struct Node n; /* the node we add each item */ if( argc != 2 ) { fprintf( stderr, "Usage: citytemp filename.ext/n"); exit( EXIT_FAILURE ); } fin = fopen( argv[1], "rt"); if ( fin==NULL ) { fprintf( stderr, "Cannot open/find %s/n", argv[2]); exit( EXIT_FAILURE ); } /** Create and initialize the linked list to empty */ CreateList(); /** main loop **/ while (!feof(fin)) { /* read a record consisting of a line of text */ if ( fgets( buffer, BUFFER_LEN, fin ) == NULL ) break; /* get rid of the trailing carriage return , delele the charater '/n' */ buffer[strlen(buffer)-1] = '/0' ; /* copy the city name to the node to be added */ n.City = strdup(buffer+3); /* mark off the temperature and convert to int */ buffer[3] = '/0'; n.Temp = atoi(buffer); /* add the node to the list */ if( AddNodeAscend( &n ) == 0) { fprintf( stderr, "Error adding node. Aborting/n"); exit( EXIT_FAILURE ); } } ShowNodes(); /* Now, delete something */ printf("/n"); DeleteNode( Head ); ShowNodes(); while (Head && Head->Next) { printf("/n"); DeleteNode(Head->Next); ShowNodes(); } printf("/n"); DeleteNode(Head); ShowNodes(); fclose(fin); return (EXIT_SUCCESS); } /** 阅读后注释: 本程序摘自《程序员实用算法》,代码给我的最大印象就是十分简洁和灵活。其特点在于: 1.向链接插入数据是通过复写完成,即使用memcpy,这样的好处就在于可以使用非指针变量 插入数据,尽量避免了指针多指向可能导致内存泄漏的问题。所以可以看到,在main函数 第178行,使用struct Node n;这一指针变量完成建链过程。链表的内存分配和释放完全由 链表本身管理。 2.使用哑元指针避免复杂的链表操作逻辑。AddNodeAscend第四十二行使用一个非指针成员dummy 作为一个哑表头,从而可以把空链,只有一个头结点和一般结点插入的情况统一。 3.使用strdup进行字符串子串的拷贝,注意与strncpy的区别。 4.最后需要说明的,代码基本上与链接保存数据无关,只要修改链接结点内部保存数据的定义, 及NodeCmp及DuplicateNode()即可移植到别的应用中。 5.上述代码中,可以看到单链表的不足之外就在需要prev指针记录当前结点的前指针位置。可以 采用Link*或双向链表改进! **/