371 lines
11 KiB
C
371 lines
11 KiB
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->have_same_cmp = list_have_same_cmp;
|
||
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;
|
||
}
|
||
|
||
int list_have_same_cmp(List l, void *data)
|
||
{
|
||
if(l != NULL)
|
||
{
|
||
Node curr;
|
||
|
||
for(curr = l->head->next; curr != NULL; curr = curr->next)
|
||
{
|
||
if(memcmp(curr->data, data, l->data_size))
|
||
{
|
||
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;
|
||
}
|