C通用鏈表庫(1.0版)
轉載自網絡。
本鏈表庫可以使用CodeBlocks(MingW)和VC系列編譯器進行編譯,爲單向帶頭尾的鏈表,封裝後使用起來很簡單,實現了鏈表的增,刪,改,排序,清空,遍歷等常用操作,可進行元素的前插和尾插,還有兩個功能,插入排序和清除重複元素,準備在下一版實現。
頭文件:list.h
#ifndef LIST_H_H
#define LIST_H_H
#include <stdio.h>
#include <malloc.h>
#include <string.h>
typedef struct clist *List;
typedef int (*compare)(void *ndata, void *data);
typedef void (*dofunc)(void *ndata);
typedef int (*lpf0)(List l, void *data);
typedef int (*lpf1)(List l, void *data, compare pfunc);
typedef List (*lpf2)(List l);
typedef void (*lpf3)(List l);
typedef void (*lpf4)(List l, dofunc pfunc);
typedef int (*lpf5)(List l, unsigned int index, void *new_data);
typedef void (*lpf6)(List l, compare pfunc);
typedef int (*lpf7)(List l, unsigned int index);
typedef struct cnode
{
void *data;
struct cnode *next;
}node, *Node;
typedef struct clist
{
Node head;
Node tail;
unsigned int size;
unsigned int data_size;
lpf0 add_back;
lpf0 add_front;
lpf1 delete_node;
lpf1 have_same;
lpf4 foreach;
lpf3 clear;
lpf2 destroy;
lpf5 modify_at;
lpf6 sort;
lpf7 delete_at;
}list;
//初始化鏈表
List list_init(unsigned int data_size);
int list_add_back(List l, void *data);
int list_add_front(List l, void *data);
int list_delete_node(List l, void *data, compare pfunc);
int list_delete_at(List l, unsigned int index);
int list_modify_at(List l, unsigned int index, void *new_data);
int list_have_same(List l, void *data, compare pfunc);
void list_foreach(List l, dofunc doit);
void list_sort(List l, compare pfunc);
void list_clear(List l);
//釋放鏈表
List list_destroy(List l);
#endif
----------------------------------------------------------------------------------------------------------------------------------------
實現文件:list_impl.c
#include "list.h"
/// 文件:list_impl.c
/// 功能:實現鏈表的基本操作
/// 作者:bluewind
/// 完成時間:2011.5.29
/// 修改時間:2011.5.31, 2011.7.2
/// 修改備註:在頭節點處添加一個空節點,可以優化添加、刪除節點代碼
/// 再次修改,鏈表增加節點數據data_size,限制數據大小,修改了
/// 添加複製數據代碼,修正重複添加節點後釋放節點的Bug,添加了前
/// 插、排序和遍歷功能,7.3 添加tail尾指針,改進後插法性能,並改名
/// --------------------------------------------------------------
void swap_data(Node n1, Node n2);
/// --------------------------------------------------------------
// 函數名:list_init
// 功能: 鏈表初始化
// 參數: 無
// 返回值:已初始化鏈表指針
// 備註: 鏈表本身動態分配,由list_destroy函數管理釋放
/// --------------------------------------------------------------
List list_init(unsigned int data_size)
{
List list = (List) malloc(sizeof(struct clist));
if(list != NULL) //內存分配成功
{
list->head = (Node) malloc(sizeof(node)); //爲頭節點分配內存
if(list->head) //內存分配成功
{
list->head->data = NULL; //初始化頭節點
list->head->next = NULL;
list->data_size = data_size;
list->tail = list->head;
list->size = 0;
list->add_back = list_add_back; //初始化成員函數
list->add_front = list_add_front;
list->delete_node = list_delete_node;
list->delete_at = list_delete_at;
list->modify_at = list_modify_at;
list->have_same = list_have_same;
list->foreach = list_foreach;
list->clear = list_clear;
list->sort = list_sort;
list->destroy = list_destroy;
}
}
return list;
}
/// --------------------------------------------------------------
// 函數名:list_add_back
// 功能: 添加鏈表結點 (後插法)
// 參數: l--鏈表指針,data--鏈表數據指針,可爲任意類型
// 返回值:int型,爲1表示添加成功,爲0表示添加失敗
// 備註: 如果鏈表本身爲空或是分配節點內存失敗,將返回0
/// --------------------------------------------------------------
int list_add_back(List l, void *data)
{
Node new_node = (Node) malloc(sizeof(node));
if(l != NULL && new_node != NULL) //鏈表本身不爲空,且內存申請成功
{
new_node->data = malloc(l->data_size);
memcpy(new_node->data, data, l->data_size);
new_node->next = NULL;
l->tail->next = new_node; //添加節點
l->tail = new_node; //記錄尾節點位置
l->size ++; //鏈表元素總數加1
return 1;
}
return 0;
}
/// --------------------------------------------------------------
// 函數名:list_add_front
// 功能: 添加鏈表結點 (前插法)
// 參數: l--鏈表指針,data--鏈表數據指針,可爲任意類型
// 返回值:int型,爲1表示添加成功,爲0表示添加失敗
// 備註: 如果鏈表本身爲空或是分配節點內存失敗,將返回0
/// --------------------------------------------------------------
int list_add_front(List l, void *data)
{
Node new_node = (Node) malloc(sizeof(node));
if(l != NULL && new_node != NULL)
{
new_node->data = malloc(l->data_size);
memcpy(new_node->data, data, l->data_size);
new_node->next = l->head->next;
l->head->next = new_node;
if(!l->size) //記錄尾指針位置
l->tail = new_node;
l->size ++;
return 1;
}
return 0;
}
/// --------------------------------------------------------------
// 函數名:list_delete_node
// 功能:刪除鏈表結點
// 參數:l--鏈表指針,data--鏈表數據指針,可爲任意類型
// *pfunc爲指向一個數據類型比較的函數指針
// 返回值:int型,爲1表示刪除成功,爲0表示沒有找到匹配數據
// 備註:*pfunc函數接口參數ndata爲節點數據,data爲比較數據,返回爲真表示匹配數據
/// --------------------------------------------------------------
int list_delete_node(List l, void *data, int (*pfunc)(void *ndata, void *data))
{
if(l != NULL)
{
Node prev = l->head; //前一個節點
Node curr = l->head->next; //當前節點
while(curr != NULL)
{
if(pfunc(curr->data, data)) //如果找到匹配數據
{
if(curr == l->tail) //如果是刪除尾節點
l->tail = prev;
prev->next = prev->next->next; //修改前節點next指針指向下下個節點
free(curr->data); //釋放節點數據
free(curr); //釋放節點
l->size--; //鏈表元素總數減1
return 1; //返回真值
}
prev = prev->next; //沒有找到匹配時移動前節點和當前節點
curr = curr->next;
}
}
return 0; //沒有找到匹配數據
}
/// --------------------------------------------------------------
// 函數名:list_delete_at
// 功能: 修改鏈表節點元素值
// 參數: l--鏈表指針,index--索引值, 範圍(0 -- size-1)
// 返回值:int型,爲1表示刪除成功,爲0表示刪除失敗
// 備註: 如果鏈表本身爲空或是index爲非法值,將返回0
/// --------------------------------------------------------------
int list_delete_at(List l, unsigned int index)
{
unsigned int cindex = 0;
if(l != NULL && index >= 0 && index < l->size)
{
Node prev = l->head; //前一個節點
Node curr = l->head->next; //當前節點
while(cindex != index)
{
prev = prev->next;
curr = curr->next;
cindex ++;
}
if(index == (l->size) - 1)
l->tail = prev;
prev->next = prev->next->next;
free(curr->data);
free(curr);
l->size --;
return 1;
}
return 0;
}
/// --------------------------------------------------------------
// 函數名:list_modify_at
// 功能: 修改鏈表節點元素值
// 參數: l--鏈表指針,index--索引值, 範圍(0 -- size-1)
// data--鏈表數據指針
// 返回值:int型,爲1表示修改成功,爲0表示修改失敗
// 備註: 如果鏈表本身爲空或是index爲非法值,將返回0
/// --------------------------------------------------------------
int list_modify_at(List l, unsigned int index, void *new_data)
{
unsigned int cindex = 0;
if(l != NULL && index >= 0 && index < l->size ) //非空鏈表,並且index值合法
{
Node curr = l->head->next;
while(cindex != index)
{
curr = curr->next;
cindex ++;
}
memcpy(curr->data, new_data, l->data_size);
return 1;
}
return 0;
}
/// --------------------------------------------------------------
// 函數名:list_sort
// 功能: 鏈表排序
// 參數: l--鏈表指針,*pfunc爲指向一個數據類型比較的函數指針
// 返回值:無
// 備註: 使用簡單選擇排序法,相比冒泡法每次交換,效率高一點
/// --------------------------------------------------------------
void list_sort(List l, compare pfunc)
{
if(l != NULL)
{
Node min, icurr, jcurr;
icurr = l->head->next;
while(icurr)
{
min = icurr; //記錄最小值
jcurr = icurr->next; //內循環指向下一個節點
while(jcurr)
{
if(pfunc(min->data, jcurr->data)) //如果找到n+1到最後一個元素最小值
min = jcurr; //記錄下最小值的位置
jcurr = jcurr->next;
}
if(min != icurr) //當最小值位置和n+1元素位置不相同時
{
swap_data(min, icurr); //才進行交換,減少交換次數
}
icurr = icurr->next;
}
}
}
void swap_data(Node n1, Node n2)
{
void *temp;
temp = n2->data;
n2->data = n1->data;
n1->data = temp;
}
int list_have_same(List l, void *data, int (*pfunc)(void *ndata, void *data))
{
if(l != NULL)
{
Node curr;
for(curr = l->head->next; curr != NULL; curr = curr->next)
{
if(pfunc(curr->data, data))
{
return 1;
}
}
}
return 0;
}
/// --------------------------------------------------------------
// 函數名:list_foreach
// 功能: 遍歷鏈表元素
// 參數: l--鏈表指針,doit爲指向一個處理數據的函數指針
// 返回值:無
// 備註: doit申明爲void (*dofunc)(void *ndata)原型
/// --------------------------------------------------------------
void list_foreach(List l, dofunc doit)
{
if(l != NULL)
{
Node curr;
for(curr = l->head->next; curr != NULL; curr = curr->next)
{
doit(curr->data);
}
}
}
/// --------------------------------------------------------------
// 函數名:list_clear
// 功能: 清空鏈表元素
// 參數: l--鏈表指針
// 返回值:無
// 備註: 沒有使用先Destroy再Init鏈表的辦法,直接實現
/// --------------------------------------------------------------
void list_clear(List l)
{
if(l != NULL)
{
Node temp;
Node curr = l->head->next;
while(curr != NULL)
{
temp = curr->next;
free(curr->data); //釋放節點和數據
free(curr);
curr = temp;
}
l->size = 0; //重置鏈表數據
l->head->next = NULL;
l->tail = l->head;
}
}
/// --------------------------------------------------------------
// 函數名:list_destroy
// 功能: 釋放鏈表
// 參數: l--鏈表指針
// 返回值:空鏈表指針
/// --------------------------------------------------------------
List list_destroy(List l)
{
if(l != NULL)
{
Node temp;
while(l->head)
{
temp = l->head->next;
if(l->head->data != NULL) //如果是頭節點就不釋放數據空間
free(l->head->data); //先釋放節點數據(但是節點數據裏也有指針?)
free(l->head); //再釋放節點
l->head = temp;
}
free(l); //釋放鏈表本身佔用空間
l = NULL;
}
return l;
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------
測試用例:main.c
#include "..\list.h"
#include <stdio.h>
typedef struct tag_msg
{
int x;
}msg, *Msg;
typedef struct foo
{
char a;
char b;
char c;
char d;
char e;
}Foo, *Pfoo;
int compare_data(void *ndata, void *data);
void show_data(void *ndata);
int compare2(void *ndata, void *data);
int main()
{
List list = NULL;
Node current;
Msg m1, m2, m3, m4, m5;
msg m6;
Foo f1;
unsigned int i;
unsigned int data_size;
data_size = sizeof(msg);
list = list_init(data_size);
m1 = (Msg) malloc(sizeof(msg));
m2 = (Msg) malloc(sizeof(msg));
m3 = (Msg) malloc(sizeof(msg));
m4 = (Msg) malloc(sizeof(msg));
m5 = (Msg) malloc(sizeof(msg));
m1->x = 100;
m2->x = 200;
m3->x = 300;
m4->x = 400;
m5->x = 500;
m6.x = 600;
f1.a = 2;
f1.b = 1;
f1.c = 0;
f1.d = 0;
f1.e = 0;
//添加測試
list->add_front(list, m1);
list->add_front(list, m2);
list->add_front(list, m3);
list->add_front(list, m4);
list->add_back(list, m2);
list->add_back(list, m3);
list->add_back(list, &m6);
list->add_back(list, &f1);
free(m1);
current = list->head->next;
for(i = 0; i < (list->size); i++)
{
printf("data of msg is %d\n",
((Msg)(current->data))->x);
current = current->next;
}
//刪除測試
if(list_delete_node(list, &m6, compare_data))
{
printf("\nDelete node OK!\n");
}
else
{
printf("\nNode data not found!\n");
}
list->add_back(list, m4);
//清空測試
//list->clear(list);
//修改測試
if(list->modify_at(list, 6, m2))
{
printf("\nModity data OK!\n\n");
}
else
{
printf("\nModify data faile!\n\n");
}
//list_delete_at(list, 0);
//list->add_back(list, m2);
list->add_back(list, &m6);
list->add_front(list, &f1);
list->add_back(list, &f1);
list->foreach(list, show_data);
//排序測試
list_sort(list, compare2);
printf("sort after:\n");
list->foreach(list, show_data);
list_destroy(list);
free(m4);
free(m5);
return 0;
}
//實現數據比較
int compare_data(void *ndata, void *data)
{
if(((Msg)(ndata))->x == ((Msg)(data))->x)
{
return 1;
}
return 0;
}
int compare2(void *ndata, void *data)
{
if( ((Msg)ndata)->x > ((Msg)data)->x )
return 1;
return 0;
}
//實現遍歷數據, 用於list->foreach
void show_data(void *ndata)
{
printf("data of msg is %d\n",
((Msg)(ndata))->x);
}