引言:
单链表存在一个问题,当我们想要访问某个结点的前一个结点时,要从头结点开始访问。显然这样的操作是令人烦躁的。为此,双向链表出现,它比单链表多出了一个指针域,指向前一个结点。这样,对于双向链表,就可以方便的从后向前遍历链表了。但多出的问题是对于插入和删除结点的开销要增加一倍。
分析描述:
双向链表存储结构图为:,用结构体表示如下:
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *prior;
struct LNode *next;
}LNode, *PLNode;
双向链表的初始化。双向链表的初始化,即分配一个LNode结构体大小的内存,使它的prior指针和next指针都指向结点本身。
PLNode InitDList(void)
{
PLNode HeadLNode = (PLNode)malloc(sizeof(LNode));
if(HeadLNode == NULL){
printf("malloc memory fail.\n");
return NULL;
}
HeadLNode->prior = HeadLNode->next = HeadLNode;
return HeadLNode;
}
双向链表创建链表。向已经初始化的双向链表的头部插入结点元素。
PLNode CreateDList(PLNode PHeadNode)
{
PLNode TmpLNode = (PLNode)malloc(sizeof(LNode));
if(TmpLNode == NULL){
printf("malloc memory fail.\n");
return PHeadNode;
}
TmpLNode->next = NULL;
while(scanf("%d", &TmpLNode->data) != 0){
TmpLNode->next = PHeadNode->next;
TmpLNode->prior = PHeadNode;
PHeadNode->next = TmpLNode;
if(TmpLNode->next != NULL)//此处的判断是针对空链表的操作,如果是空链表,下面的语句就不做。
TmpLNode->next->prior = TmpLNode;
TmpLNode = (PLNode)malloc(sizeof(LNode));
if(TmpLNode == NULL){
return PHeadNode;
}
}
free(TmpLNode);
return PHeadNode;
}
双向链表的遍历。此处的链表的遍历与前面提到的单链表的遍历没有什么不同。需要注意的地方还是对参数的保护。
void TraverseDList(PLNode PHeadNode)
{
PLNode TmpLNode = PHeadNode;
if(PHeadNode == NULL) {
printf("input element faulse.\n");
return ;
}
while(TmpLNode->next != NULL){
printf("%d ", TmpLNode->next->data);
TmpLNode = TmpLNode->next;
}
putchar('\n');
}
双向链表的长度。跟求单链表长度一样。
int ListLength(PLNode PHeadNode)
{
int count = 0;
while(PHeadNode->next != NULL){
count++;
PHeadNode = PHeadNode->next;
}
return count;
}
双向链表中插入节点元素。 给定一个双向链表和插入位置,给定一个结点元素,向给定的链表中插入该结点。
PLNode InsertDList(PLNode PHeadNode, ElemType data, int Index)
{
int index = 0;
PLNode TmpLNode = PHeadNode;
if(PHeadNode == NULL || Index < 0 || Index > ListLength(PHeadNode) + 1){
printf("input element faulse.\n");
return NULL;
}
for(index = 1; index < Index; index++){
TmpLNode = TmpLNode->next;
}
PLNode Tmp = (PLNode)malloc(sizeof(LNode));
if(Tmp == NULL){
printf("malloc memory faluse.\n");
return PHeadNode;
}
Tmp->data = data;
Tmp->next = TmpLNode->next;
Tmp->prior = TmpLNode->prior;
TmpLNode->next = Tmp;
TmpLNode->prior = Tmp;
return PHeadNode;
}
双向链表中删除结点。
PLNode DeleteList(PLNode PHeadNode, int Index)
{
int index;
PLNode TmpNode = PHeadNode;
if(PHeadNode == NULL || Index < 0 || Index > ListLength(PHeadNode)){
printf("input element faulse.\n");
return NULL;
}
for(index = 0; index < Index; index++){
TmpNode = TmpNode->next;
}
TmpNode->prior->next = TmpNode->next;
if(TmpNode->next != NULL)
TmpNode->next->prior = TmpNode->prior;
free(TmpNode);
return PHeadNode;
}
双向链表中删除结点。
PLNode DeleteList(PLNode PHeadNode, int Index)
{
int index;
PLNode TmpNode = PHeadNode;
if(PHeadNode == NULL || Index <= 0 || Index > ListLength(PHeadNode)){
printf("input element faulse.\n");
return NULL;
}
for(index = 0; index < Index; index++){
TmpNode = TmpNode->next;
}
TmpNode->prior->next = TmpNode->next;
TmpNode->next->prior = TmpNode->prior;
free(TmpNode);
return PHeadNode;
}