一、概述
双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。它其实就是单链表的基础上加入了前驱指针,能够很方便的访问它的前一个数据节点。
从图中可以看出我们的struct需要3个成员:data、prio 、next;
我们再加入一些链表的基本操作可得:
#pragma once
//预防头文件被重复使用
typedef struct DNode
{
int data;
struct DNode *next;//后继指针
struct DNode *prio;//前驱指针
}DNode,*DList;
void InitList(DList plist);
//头插
bool Insert_head(DList plist,int val);
//尾插
bool Insert_tail(DList plist,int val);
DNode *Search(DList plist,int key);
bool Delete(DList plist,int key);
bool IsEmpty(DList plist);
int GetLength(DList plist);
void Show(DList plist);
接下来是各个部分功能的实现:
void InitList(DList plist)//初始化
{
assert(plist != NULL);判断链表是否成功生成
if(plist == NULL)
{
return ;
}
plist->prio = NULL;制成空指针
plist->next = NULL;
}
头插法:
bool Insert_head(DList plist,int val)
{
DNode *p = (DNode *)malloc(sizeof(DNode));//在堆上开辟新的节点
p->data = val;//把数据赋给data
p->next = plist->next;//先将数据连起来,防止数据丢失
plist->next = p;连接后继
p->prio = plist;//连接前驱
if(p->next != NULL)//判断该节点的下个节点是否有节点,有就要连接下个节
// 点的前驱
{
p->next->prio = p;连接后继的前驱
}
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;
q->prio = plist;
if(p->next != NULL)
{
p->next->prio = p;
}
return true;
}
获得链表长度:int GetLength(DList plist)
{
DNode *p;
int count = 0;//计数器
for(p=plist;p->next != NULL;p=p->next)
{
count++;
}
return count;
}
查找节点:
DNode *Search(DList plist,int key)
{
DNode *p;
for(p=plist;p->next!= NULL;p=p->next)//遍历找key
if(p->data == key)
{
return p;
}
}
return NULL;
}
删除节点:可以利用查找函数,找到之后free它
bool Delete(DList plist,int key)
{
DNode *p;
p = Search(plist,key);
if(p == NULL) //d等于空说明没有找到
{
return false;
}
p->prio->next = p->next;//穿过它,将它前一个节点的下一个节点给它的下一个节点
if(p->next != NULL)
{
p->next->prio = p->prio;//如果后面还有数据,将它的后面也处理好(将后继的前驱制成自己)
}
free(p);
return true;
}

bool Delete(DList plist,int key)
{
DNode *p;
p = Search(plist,key);
if(p == NULL) //d等于空说明没有找到
{
return false;
}
p->prio->next = p->next;//穿过它,将它前一个节点的下一个节点给它的下一个节点
if(p->next != NULL)
{
p->next->prio = p->prio;//如果后面还有数据,将它的后面也处理好(将后继的前驱制成自己)
}
free(p);
return true;
}
销毁:
void Destroy(DList plist)
{
DNode *p;
while(plist->next!= plist->prio)
{
p = plist->next;
plist->next = p->next;
free(p);
}
}
程序测试:
void Destroy(DList plist)
{
DNode *p;
while(plist->next!= plist->prio)
{
p = plist->next;
plist->next = p->next;
free(p);
}
}
#include<stdio.h>
#include"dlist.h"
#include<vld.h>
int main()
{
DNode sa;
InitList(&sa);
int i;
for(i=0;i<10;i++)
{
Insert_head(&sa,i );
}
Show(&sa);
printf("%d\n",GetLength(&sa));
Delete(&sa,1);
Delete(&sa,2);
Delete(&sa,4);
Delete(&sa,9);
//Destroy(&sa);
//Destroy(&sa);
//Destroy(&sa);
Show(&sa);
printf("%d\n",Search(&sa,7));
}
运行结果:
#include<stdio.h>
#include"dlist.h"
#include<vld.h>
int main()
{
DNode sa;
InitList(&sa);
int i;
for(i=0;i<10;i++)
{
Insert_head(&sa,i );
}
Show(&sa);
printf("%d\n",GetLength(&sa));
Delete(&sa,1);
Delete(&sa,2);
Delete(&sa,4);
Delete(&sa,9);
//Destroy(&sa);
//Destroy(&sa);
//Destroy(&sa);
Show(&sa);
printf("%d\n",Search(&sa,7));
}