双向链表
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
双链表结构如下:
typedef int DataType;
typedef struct DoubleNode
{
struct DoubleNode* prev; //指向前一节点的指针
struct DoubleNode* next; //指向后一节点的指针
DataType data; //当前节点的数据
}DoubleNode,*DoubleList;
DoubleList end = NULL; //记录最后一个节点的位置
跟单链表相似,只是双链表比单链表多了一个指向前驱的指针。
这样我们在插入和删除一个节点的时候,不必遍历链表找到该节点的前一个节点了。
双链表的一些基本操作实现如下:
void InitDoubleList(DoubleList* pDlist) //初始化
{
assert(pDlist);
*pDlist = NULL;
}
void PrintDoubleList(DoubleList pDlist) //打印双向链表
{
if (pDlist == NULL)
{
printf("DoubleList Is Empty\n");
return;
}
printf("DoubleList->");
DoubleList begin = pDlist;
while (begin)
{
printf("%d->", begin->data);
begin = begin->next;
}
printf("NULL\n");
}
DoubleList GreateDoubleNode(DataType data) //增加节点
{
DoubleList tmp = (DoubleList)malloc(sizeof(DoubleNode));
tmp->data = data;
tmp->next = NULL;
tmp->prev = NULL;
return tmp;
}
void PushBack(DoubleList* pDlist,DataType data) //尾插一个节点
{
assert(pDlist);
if (*pDlist == NULL)
{
*pDlist = GreateDoubleNode(data);
end = *pDlist;
return;
}
DoubleList tmp = GreateDoubleNode(data);
end->next = tmp;
tmp->prev = end;
end = tmp;
}
void PopBack(DoubleList* pDlist) //尾删一个节点
{
assert(pDlist);
if (*pDlist == NULL) //空链表
{
printf("DoubleList Is Empty\n");
return;
}
if ((*pDlist)->next == NULL) //只有一个节点
{
free(*pDlist);
*pDlist = NULL;
return;
}
DoubleList del = end;
end = end->prev;
end->next = NULL;
free(del);
}
void PushFront(DoubleList* pDlist, DataType data) //头插一个节点
{
assert(pDlist);
if (*pDlist == NULL)
{
*pDlist = GreateDoubleNode(data);
end = *pDlist;
return;
}
DoubleList ret = GreateDoubleNode(data);
ret->next = *pDlist;
(*pDlist)->prev = ret;
*pDlist = ret;
}
void PopFront(DoubleList* pDlist) //头删一个节点
{
assert(pDlist);
if (*pDlist == NULL)
{
printf("DoubleList Is Empty\n");
return;
}
if ((*pDlist)->next == NULL) //只有一个节点
{
free(*pDlist);
*pDlist = NULL;
return;
}
DoubleList del = *pDlist;
*pDlist = (*pDlist)->next;
(*pDlist)->prev = NULL;
free(del);
}
DoubleList Find(DoubleList pDlist, DataType data) //查找节点
{
if (pDlist == NULL)
{
printf("DoubleList Is Empty\n");
return NULL;
}
DoubleList begin = pDlist;
while (begin)
{
if (begin->data == data)
{
return begin;
}
begin = begin->next;
}
return NULL;
}
void Insert(DoubleList* pDlist, DoubleList n, DataType data)//在节点n后插入一个节点
{
assert(pDlist);
if (*pDlist == NULL)
{
printf("DoubleList Is Empty\n");
}
else if (n == NULL)
{
printf("n Not Exist\n");
}
else
{
if (n == end)
{
PushBack(pDlist, data);
}
else
{
DoubleList ret = GreateDoubleNode(data);
DoubleList tmp = n->next;
ret->next = tmp;
ret->prev = n;
tmp->prev = ret;
n->next = ret;
}
}
}
void DelDoubleNode(DoubleList* pDlist,DoubleList n) //删除节点n
{
assert(pDlist);
if (*pDlist == NULL)
{
printf("DoubleList Is Empty\n");
}
else if ((*pDlist)->next == NULL && n == *pDlist)//只有一个节点且查找的正是这个节点
{
free(*pDlist);
*pDlist = NULL;
}
else
{
if (n == *pDlist)
{
PopFront(pDlist);
}
else if (n == end)
{
PopBack(pDlist);
}
else
{
DoubleList prev = n->prev;
DoubleList next = n->next;
next->prev = prev;
prev->next = next;
free(n);
}
}
}
void Reverse(DoubleList* pDlist) //逆置双向链表
{
assert(pDlist);
if (*pDlist == NULL || (*pDlist)->next == NULL)
{
return;
}
DoubleList begin = (*pDlist)->next;
begin->prev = NULL;
(*pDlist)->next = NULL; //摘下头节点作为尾节点
while (begin)
{
DoubleList ret = begin;
begin = begin->next;
ret->next = *pDlist;
ret->prev = NULL;
(*pDlist)->prev = ret;
*pDlist = ret; //更新逆置后的头节点
}
}
双向链表相比较单向链表,主要有下面几个特点:
**(1)在数据结构中具有双向指针** **(2)插入数据的时候需要考虑前后的方向的操作** **(3)同样,删除数据的是有也需要考虑前后方向的操作**