1、双向链表的定义
在单链表的结点中增加一个指向其前驱的p r e指针!
2、数据结构的定义
//dlinklist.h
/*
对外做数据封装,屏蔽线性表的实现
*/
typedef void DLinklist;
typedef struct _struct_linklistNode DLinklistNode;
struct _struct_linklistNode
{
DLinklistNode *pre;
DLinklistNode *next;
};
//dlinklist.c
//内部头结点的真实定义
typedef struct _struct_dlinklist
{
DLinklistNode header;
//游标成员
DLinklistNode *silder;
int length;
}TDLinklist;
//main.c
//被插入元素的定义
typedef struct _struct_value
{
DLinklistNode node;
int v;
}Value;
3、创建操作
/*
该方法用于创建并且返回一个空的线性表
*/
DLinklist* List_Create()
{
TDLinklist *tlist = NULL;
tlist = (TDLinklist*)malloc(sizeof(TDLinklist));
if(tlist != NULL)
{
tlist->header.pre = NULL;
tlist->header.next = NULL;
tlist->silder = NULL;
tlist->length = 0;
}
return tlist;
}
4、插入操作
示意图:
/*
该方法用于向一个线性表list的pos位置处插入新元素node
返回值为1表示插入成功,0表示插入失败
*/
int List_Insert(DLinklist* list, DLinklistNode* node, int pos)
{
int iret = 1;
TDLinklist *tlist = (TDLinklist*)list;
iret = iret && (tlist != NULL) && (node != NULL) && (pos >= 0);
if(iret)
{
DLinklistNode *current = (DLinklistNode*)tlist;
DLinklistNode *next = NULL;
for(int i = 0; (i<pos) && (current->next != NULL); i++)
{
current = current->next;
}
next = current->next;
current->next = node;
node->next = next;
if(next != NULL)
{
next->pre = node;
}
node->pre = current;
if(tlist->length == 0)
{
//如果插入的是第一个元素,则默认让游标指向它
//游标默认指向第一个插入的元素
tlist->silder = tlist->header.next;
}
//如果插入的位置是第一个元素,则修正新的第一个元素的pre指针
if(current == (DLinklistNode*)tlist)
{
//让第一个元素的pre指向NULL
node->pre = NULL;
//添加如下的代码,可让游标始终指向链表的第一个元素
//tlist->silder = tlist->header.next;
}
tlist->length++;
}
return iret;
}
5、删除操作
示意图:
/*
该方法用于删除一个线性表list的pos位置处的元素
返回值为被删除的元素,NULL表示删除失败
*/
DLinklistNode* List_Delete(DLinklist* list, int pos)
{
DLinklistNode *ret = NULL;
TDLinklist *tlist = (TDLinklist*)list;
if(tlist != NULL)
{
//要保证被删除的元素存在, && (tlist->length > 0)
if((pos >= 0)&&(pos < tlist->length))
{
DLinklistNode *current = (DLinklistNode*)tlist;
DLinklistNode *next = NULL;
for(int i = 0;i<pos;i++)
{
current = current->next;
}
ret = current->next;
next = ret->next;
current->next = ret->next;
if(next != NULL)
{
next->pre = current;
//以下条件等价于:current == (DLinklistNode*)tlist
if(pos == 0)
{
next->pre = NULL;
}
}
//如果游标当前指向了要删除的元素,则让游标指向它的下一个元素
if(ret == tlist->silder)
{
tlist->silder = ret->next;
}
ret->pre = NULL;
ret->next = NULL;
tlist->length--;
}
}
return ret;
}
6、增加游标后的新操作
- 获取当前游标指向的数据元素
- 将游标重置指向链表中的第一个数据元素
- 将游标移动指向到链表中的下一个数据元素
- 将游标移动指向到链表中的上一个数据元素
- 直接指定删除链表中的某个数据元素
相关定义:
/*
删除指定结点
如果成功,返回被删除的结点,否则返回NULL
*/
DLinklistNode* List_DeleteNode(DLinklist *list,DLinklistNode *node);
/*
重置游标
如果成功,返回重置后的元素,否则返回NULL
*/
DLinklistNode* List_Reset(DLinklist *list);
/*
获取当前游标指向的元素
如果成功,返回当前游标指向的元素,否则返回NULL
*/
DLinklistNode* List_Current(DLinklist *list);
/*
让游标指向下一个元素
如果成功,返回下一个元素,否则返回NULL
特殊情况:链表最后一个元素的下一个元素也为NULL
*/
DLinklistNode* List_Next(DLinklist *list);
/*
让游标指向前一个元素
如果成功,返回前一个元素,否则返回NULL
特殊情况:链表的第一个元素的前一个元素也为NULL
*/
DLinklistNode* List_Pre(DLinklist *list);
相关实现:
/*
删除指定结点
如果成功,返回被删除的结点,否则返回NULL
*/
DLinklistNode* List_DeleteNode(DLinklist *list,DLinklistNode *node)
{
DLinklistNode *ret = NULL;
TDLinklist *tlist = (TDLinklist*)list;
if((tlist != NULL) && (node != NULL))
{
int i = 0;
DLinklistNode *current = (DLinklistNode*)tlist;
for(i = 0;i < tlist->length;i++)
{
current = current->next;
if(current == node)
{
ret = current;
break;
}
}
//判断是否找到要删除的元素
if(ret != NULL)
{
List_Delete(list,i);
}
}
return ret;
}
/*
重置游标
如果成功,返回重置后的元素,否则返回NULL
*/
DLinklistNode* List_Reset(DLinklist *list)
{
DLinklistNode *ret = NULL;
TDLinklist *tlist = (TDLinklist*)list;
if(tlist != NULL)
{
tlist->silder = tlist->header.next;
ret = tlist->silder;
}
return ret;
}
/*
获取当前游标指向的元素
如果成功,返回当前游标指向的元素,否则返回NULL
*/
DLinklistNode* List_Current(DLinklist *list)
{
DLinklistNode *ret = NULL;
TDLinklist *tlist = (TDLinklist*)list;
if(tlist != NULL)
{
ret = tlist->silder;
}
return ret;
}
/*
让游标指向下一个元素
如果成功,返回下一个元素,否则返回NULL
特殊情况:链表最后一个元素的下一个元素也为NULL
*/
DLinklistNode* List_Next(DLinklist *list)
{
DLinklistNode *ret = NULL;
TDLinklist *tlist = (TDLinklist*)list;
if(tlist != NULL)
{
tlist->silder = tlist->silder->next;
ret = tlist->silder;
}
return ret;
}
/*
让游标指向前一个元素
如果成功,返回前一个元素,否则返回NULL
特殊情况:链表的第一个元素的前一个元素也为NULL
*/
DLinklistNode* List_Pre(DLinklist *list)
{
DLinklistNode *ret = NULL;
TDLinklist *tlist = (TDLinklist*)list;
if(tlist != NULL)
{
tlist->silder = tlist->silder->pre;
ret = tlist->silder;
}
return ret;
}
7、小结
- 双向链表在单链表的基础上增加了指向前驱的指针
- 功能上双向链表可以完全取代单链表的使用
- 循环链表的N e xt,Pre和C u rre nt操作可以高效遍历链表中的所有元素
8、完整源码下载
文件名称:dlinklist-1.0.tar.gz
链接: http://pan.baidu.com/s/1c0bFUda 密码: 2asr
编译步骤:
0.1 解压缩:tar -zxvf dlinklist-1.0.tar.gz
0.2 进入目录:./configure
0.3 生成Seqlist:make
0.4 运行程序:./Dlinklist