一、什么是双链表
概念:在使用一个单链表时,我们可以通过next指针很轻松地访问下一个结点,但是如果想要找到一个结点的前驱结点却没有什么好的办法,只能从头开始遍历。既然我们想要很轻松地访问前驱结点,那么定义一个像next一样的指针指向前驱结点不就好了吗!确实如此,这样每个结点都有两个指针域,分别指向前驱结点和后继结点,这样的链表就是双链表。
代码:
typedef struct DNode
{
ElemType data;
struct DNode *prior, *next; //前驱结点指针,后继结点指针
}DNode, *DLinkList;
二、双链表的操作
1.初始化
①带头结点
bool InitDLinkList(DLinkList &L)
{
L = new DNode; //创建一个头结点并分配空间
if (L == NULL)
return false; //内存不足分配失败
L->prior = NULL; //头结点的prior指针永远指向NULL
L->next = NULL; //头结点后面暂时还没有结点
return true;
}
②不带头结点
bool InitDLinkList(DLinkList &L)
{
L = NULL;
return true;
}
2.判空
bool Empty(DLinkList L)
{
if (L->next ==NULL)
return true;
else
return false;
}
3.插入
bool InsertNextDNode(DNode* p, DNode* s)
{//在给定p结点后插入一个结点s
if (p == NULL || s == NULL)
return false; //传入的结点有错误
s->next = p->next; //新结点的后继结点指向p结点的后继结点
if (p->next != NULL) //如果p结点不是最后一个结点
P->next->prior = s; //p的后继结点的前驱指针指向新结点
s->prior = p; //新结点的前驱指针指向前驱结点p
p->next = s; //p结点的后继指针指向新结点,这一步要放在最后写
return true;
}
上述代码是一个结点的后插操作,得益于双链表有两个指针,所以其他的插入操作比如前插操作,按位序插入等都可以在后插的基础上很轻松地完成。
4.删除
bool DeleteNextDNode(DNode* p)
{//删除结点p的后继结点
if (p == NULL)
return false; //传入的结点有误
DNode* q = p->next; //令q指向p的后继结点
if (q == NULL)
return false; //p没有后继结点
p->next = q->next; //把要删除的结点的下一个结点接在p结点后面
if (q->next != NULL) //如果要删除的结点不是最后一个结点
q->next->prior = p;
delete q; //释放被删除结点中的数据
return true;
}
其他删除操作例如按位序删除,也可以借助上述代码完成。
5.销毁
bool DestoryList(DLinkList &L)
{//循环释放各个数据结点
while (L->next != NULL)
DeleteNextDNode(L);
delete L;
L->NULL;
return true;
}
双链表的其他操作与单链表类似,代码不再重复给出,双链表在往前找这一方面还是比较方便的。