在单链表中,通过一个结点找到它的后继结点非常容易,操作的时间复杂程度为O(1),但是要找到它的前驱结点非常麻烦,操作的时间复杂程度为O(n),因为只能从表头指针开始,沿着每个结点遍历,究其原因是单链表的各个结点只指向其后继结点的next域,如果希望查找前驱结点的时间复杂程度也为O(1),则需要为每个结点添加一个前驱指针域prio,使得链表可以双向查找。这就是双向链表。
双向链表结点的类型定义
双向链表的每个结点都有两个指针域:一个指向后继、一个指向前驱。
typedef struct DNode
{
int data;
struct DNode *next;
struct DNode *prio;
}DNode, *DList;
双向链表的初始化
void InitList(DList plist)
{
assert(plist != NULL);
if(NULL == plist)
{
return;
}
plist->next = NULL;
plist->prio = NULL;
}
双向链表的头插
bool Insert_Head(DList plist, int val)
{
DNode *p = (DNode*)malloc(sizeof(DNode));
p->data = val;
p->next = plist->next;
plist->next = p;
if (p->next == NULL)
{
return false;
}
p->next->prio = p;
p->prio = plist;
return true;
}
双向链表的尾插
bool Insert_Tail(DList plist, int val)
{
DNode *p = (DNode*)malloc(sizeof(DNode));
p->data = val;
DNode *q;
for (q = plist; q->next != NULL; q = q->next);
p->next = q->next;
q->next = p;
p->prio = q;
return true;
}
双向链表的按值删除
bool Delete(DList plist, int key)
{
DNode *p,*q;
for (p = plist; p->next != NULL; p = p->next)
{
if (p->next->data == key)
{
q = p->next;
p->next = q->next;
if (q->next != NULL)
{
q->next->prio = p;
}
}
}
free(q);
return true;
}
双向链表的销毁
void Destroy(DList plist)
{
DNode *p;
while (plist != NULL)
{
p = plist->next;
plist->next = p->next;
free(p);
}
}
双向链表的打印
void Show(DList plist)
{
for (DNode *p = plist->next; p != NULL; p = p->next)
{
printf("%d ", p->data);
}
printf("\n");
}
双向链表的实例
int main()
{
DNode head;
InitList(&head);
for (int i = 0; i < 20; i++)
{
Insert_Tail(&head, i);
}
Delete(&head, 5);
Show(&head);
return 0;
}