/*--- 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[20];
char *str = NULL;
char ch[2];
int i=0;
int flag=1;
struct List *L1, *L2;
Link w1, w2;
while(1)
{
i =0;
flag =1;
printf("please input a string\n");
str = fgets(word, 30, stdin);
while(str == NULL)
{
continue;
}
printf("%d\n",strlen(word));
word[strlen(word)-1]='\0';
printf("%s\n",word );
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 );
}
while(word[i]!='\0')
{
ch[0] = word[i];
ch[1] = 0;
if ( ! AddNodeAscend ( L1, ch ))
fprintf ( stderr,
"Warning! Error while adding node to L1.\n" );
if ( ! AddNodeAtHead ( L2, ch ))
fprintf ( stderr,
"Warning! Error while adding node to L2.\n" );
i+=1;
}
printf("%d\n", L2->LCount );
if (L2->LCount == 0)
{
printf("result = -1\n");
printf("prease input a not null string \n");
break;
}
else
{
w1 = L2->LHead;
w2 = L2->LTail;
// while((w1!=w2 || (w1->next) !=w2))
while(w1 != NULL && w2 != NULL)
{
printf("w1= %s, w2= %s \n", ((pND2) (w1->pdata))->word ,((pND2) (w2->pdata))->word);
if ( *(((pND2) (w1->pdata))->word) == *(((pND2) (w2->pdata))->word) )
{
w1 = w1->next;
w2 = w2->prev;
}
else
{
flag = 0;
printf("result = 0\n");
printf("your input is not a Symmetric string \n");
break;
}
}
if (flag == 0)
{
continue;
}
else
{
printf("result = 1\n");
printf("your input is a Symmetric string \n");
}
}
}
getchar();
return ( EXIT_SUCCESS );
}
/*--- 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 ));
}
/*--- llgen.h ----------------------------- Listing 2-2 ---------
* Declarations for generic doubly linked lists.
* Used in conjunction with llgen.c (Listing 2-3).
*-------------------------------------------------------------*/
#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 );
}