双向链表的通用模板

最近在看程序员实用算法这本书,里面用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 */
}



这个是 main 函数,测试用的,写的比较简单

/* 因为是用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 );
}


第一次写博客,谢谢大家的支持,往后我会把我会的知识都写成博客供大家学习参考!




  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

dq_zhx

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值