最近在看程序员实用算法这本书,里面用c语言写了很多商用代码,我看了之后深有感触.里面有些错误,我修正过了下面我先贴出一个双向链表的通用模板!
这个是通用模板 llgen.h 头文件,其实通用模板就是讲 data 数据独立出来,这里用 void 指针实现,讲与数据相关的函数的函数指针赋值给 List 结构.这样用户
使用模板时,只需要提供 CreateData() , DeleteData() , DuplicatedNode() , NodeDataCmp() 这四个函数.其他的函数都是通用的.
/*--- llgen.h -----------------------------------------------------------------
* Declarations for generic doubly linked lists.
* Used in conjunction with llgen.c
*---------------------------------------------------------------------------*/
#ifndef LLGEN_H
#define LLGEN_H 1
struct Node {
struct Node *prev;
struct Node *next;
void *data; /* 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 * data );
int ( *LDeleteData ) ( void * data );
int ( *LDuplicatedNode ) ( Link new_node , Link list_node );
int ( *LNodeDataCmp ) ( void * first , void * second );
};
/*--- generic linked-list primitives ---*/
extern int AddNodeAscend ( struct List * L , void * nodeData );
extern int AddNodeAtHead ( struct List * L , void * nodeData );
extern struct List * CreateLList ( void * ( *pfCreateData ) ( void * ), /* create data */
int ( *pfDeleteData ) ( void * ), /* delete data */
int ( *pfDuplicatedNode ) ( Link , Link ), /* duplicate */
int ( *pfNodeDataCmp ) ( void * , void * ) ); /* compare */
extern Link CreateNode ( struct List * L , void * dataToAdd );
extern int DeleteNode ( struct List * L , Link to_delete );
extern Link FindNode ( struct List * L , void * nodeData );
extern Link FindNodeAscend ( struct List * L , void * nodeData );
#endif
这个是 llgen.c 源文件
/*----- llgen.cpp -------------------------------------------------------------
* Generic primitive functions for doubly linked lists.
* Contains no application-specific functions.
* Functions are in alphabetical order.
*---------------------------------------------------------------------------*/
#include <stdlib.h>
#include <string.h>
#include "llgen.h"
/*--- Aliases to make the code more readable ---*/
#define LLHead (L->LHead)
#define LLTail (L->LTail)
#define NodeCount (L->LCount)
#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.
* Return 0 on error, 1 on success
*---------------------------------------------------------------------------*/
int AddNodeAtHead( struct List * L , void * nodeData )
{
Link pnode;
pnode = CreateNode( L , nodeData );
if ( NULL == pnode ) {
return ( 0 );
}
/* Add the node */
if ( NULL == LLHead ) {
LLHead = LLTail = pnode;
}
else {
LLHead->prev = pnode;
pnode->next = LLHead;
LLHead = pnode;
}
NodeCount += 1;
return ( 1 );
}
/*-----------------------------------------------------------------------------
* Add ascending. Add a node to an ordered list.
*---------------------------------------------------------------------------*/
int AddNodeAscend( struct List * L , void * nodeData )
{
Link pnode;
Link prev,curr; /* our current search */
int cmp_result;
int dup_result;
struct Node dummy;
pnode = CreateNode( L , nodeData );
if ( NULL == pnode ) {
return ( 0 );
}
/* attach dummy node to head of list
* because the node may be inserted in the header */
dummy.next = LLHead;
dummy.prev = NULL;
if ( NULL != dummy.next ) {
dummy.next->prev = &dummy;
}
prev = &dummy;
curr = dummy.next;
for ( ; NULL != curr; prev = curr,curr = curr->next ) {
cmp_result = NodeDataCmp( pnode->data , nodeData );
if ( cmp_result <= 0 ) {
break; /* new node equals or precedes curr */
}
}
if ( NULL != curr && 0 == cmp_result ) {
dup_result = DuplicatedNode( pnode , curr );
if ( 2 == dup_result ) {
/* do nothing -- will get inserted */
}
else {
/* first repair the linked list */
LLHead = dummy.next;
LLHead->prev = NULL;
/* delete the duplicated node, if appropriate */
if ( 1 == dup_result ) {
DeleteData( pnode->data );
free( pnode );
}
return ( 1 );
}
}
/* Add the node */
prev->next = pnode;
pnode->prev = prev;
pnode->next = curr;
if ( NULL != curr ) {
curr->prev = pnode;
}
else {
LLTail = pnode; /* 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.
* This functions accepts pointers to four list-specific functions
* and initializes the linked-list structure with them.
* Return NULL on error.
*---------------------------------------------------------------------------*/
struct List * CreateLList(
void * (*pfCreateData) (void *), /* create data */
int (*pfDeleteData) (void *), /* delete data */
int (*pfDuplicatedNode) (Link ,Link), /* duplicate */
int (*pfNodeDataCmp) (void *,void *)) /* compare */
{
struct List * pList;
pList = (struct List *)malloc(sizeof( struct List ));
if ( NULL == pList ) {
return ( NULL );
}
pList->LHead = NULL;
pList->LTail = NULL;
pList->LCount = 0;
pList->LCreateData = pfCreateData;
pList->LDeleteData = pfDeleteData;
pList->LDuplicatedNode = pfDuplicatedNode;
pList->LNodeDataCmp = pfNodeDataCmp;
return ( pList );
}
/*-----------------------------------------------------------------------------
* Creates a node and then calls the application-specific function CreateData()
* to create the node's data structure.
* Return NULL on error, a pointer to new node on success.
*---------------------------------------------------------------------------*/
Link CreateNode( struct List *L,void * dataToAdd )
{
Link new_node;
new_node = (Link) malloc(sizeof ( struct Node ));
if ( NULL == new_node ) {
return NULL;
}
new_node->prev = NULL;
new_node->next = NULL;
/*--- now call the application-specific data allocation ---*/
new_node->data = CreateData( dataToAdd );
if ( NULL == new_node->data ) {
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.
* Return 0 on error, 1 on success.
*---------------------------------------------------------------------------*/
int DeleteNode( struct List *L , Link to_delete )
{
Link tmp_node;
if ( NULL == to_delete ) {
return ( 0 );
}
/*--- we are in the list ---*/
if ( NULL != to_delete->prev && NULL != to_delete->next ) {
tmp_node = to_delete->prev;
tmp_node->next = to_delete->next;
tmp_node = to_delete->next;
tmp_node->prev = to_delete->prev;
}
else {
/*--- we are on the head ---*/
if ( NULL == to_delete->prev && NULL != to_delete->next ) {
LLHead = to_delete->next;
LLHead->prev = NULL;
}
/*--- we are on the tail ---*/
if ( NULL != to_delete->prev && NULL == to_delete->next ) {
LLTail = to_delete->prev;
LLTail->next = NULL;
}
/*--- the deleted node is the only one node in the list ---*/
if ( NULL == to_delete->prev && NULL == to_delete->next ) {
LLHead = NULL;
LLTail = NULL;
}
}
DeleteData( to_delete->data );
free( to_delete );
NodeCount -= 1;
return ( 1 );
}
/*-----------------------------------------------------------------------------
* Find 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 * nodeData )
{
Link curr;
int cmp_result;
if ( NULL == LLHead ) {
return ( NULL );
}
for ( curr = LLHead; NULL != curr; curr = curr->next ) {
cmp_result = NodeDataCmp( nodeData , curr->data );
if ( 0 == cmp_result ) {
return ( curr );
}
}
return ( NULL );
}
Link FindNodeAscend( struct List *L,void * nodeData )
{
Link curr;
int cmp_result;
if ( NULL == LLHead ) {
return ( NULL );
}
for ( curr = LLHead; NULL != curr; curr = curr->next ) {
cmp_result = NodeDataCmp( nodeData , curr->data );
if ( cmp_result < 0 ) {
return ( NULL );
}
if ( 0 == cmp_result ) {
return ( curr );
}
}
return ( NULL ); /* could not find node */
}
/* 因为是用VS2013写的,所以它会检查函数的安全性,手动定义这个宏之后编译器就不会检查安全性了 */
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "llgen.h"
struct tagStudent {
int ID;
char name[20];
};
typedef struct tagStudent * Student;
void * CreateData1( void * data )
{
/* In this case, data point to a character array */
Student pstu;
static int num = 1;
pstu = ( Student )malloc( sizeof( struct tagStudent ) );
if ( NULL == pstu ) {
return ( NULL );
}
pstu->ID = num++;
strncpy( pstu->name , ( char* )data , sizeof(pstu->name) );
return ( pstu );
}
int DeleteData1( void *data )
{
/* In this case, tagStudent consists of: an int and a character array
* All variables will be returned to memory when the node is freed.
* Don't need to freed manually.
*/
return ( 1 );
}
int DuplicatedNode1( Link new_node , Link list_node )
{
/* delete the duplicated node */
return ( 1 );
}
int NodeDataCmp1( void *first , void *second )
{
return ( strcmp( ( ( Student )first )->name , ( ( Student )second )->name ) );
}
/*--- test the linked-list ---*/
int main( int argc , char* argv[] )
{
FILE *fin;
struct List *List;
Link curr;
char name[20];
fin = fopen( "test.txt" , "r" );
if ( NULL == fin ) {
perror( "test.txt" );
return ( EXIT_FAILURE );
}
List = CreateLList( CreateData1 , DeleteData1 , DuplicatedNode1 , NodeDataCmp1 );
if ( NULL == List ) {
fprintf( stderr , "Error CreateLList\n" );
return ( EXIT_FAILURE );
}
while ( NULL != fgets( name , 20 , fin ) ) {
if ( strlen( name ) > 0 ) {
name[strlen( name ) - 1] = '\0'; /* strip tail \n */
}
if ( 0 == AddNodeAscend( List , name ) ) {
fprintf( stderr , "Error AddNodeAscend\n" );
return ( EXIT_FAILURE );
}
}
fclose( fin );
/* output the original linked-list */
printf( "before delete\n" );
for ( curr = List->LHead; curr != NULL; curr = curr->next ) {
printf( "ID = %d name = %s\n" , ( ( Student )( curr->data ) )->ID ,
( ( Student )( curr->data ) )->name );
}
/* delete node name for zhihenxiu */
printf( "after delete\n" );
struct tagStudent Stu;
strncpy( Stu.name , "shuihu" , sizeof( Stu.name ) );
DeleteNode( List , FindNodeAscend( List , &Stu ) );
for ( curr = List->LHead; curr != NULL; curr = curr->next ) {
printf( "ID = %d name = %s\n" , ( ( Student )( curr->data ) )->ID ,
( ( Student )( curr->data ) )->name );
}
return ( EXIT_SUCCESS );
}
第一次写博客,谢谢大家的支持,往后我会把我会的知识都写成博客供大家学习参考!