您的位置:首页 > 其它

双向链表的基本操作

2017-07-27 22:46 127 查看
   学过单向链表的小伙伴都知道单向链表中的每一个节点有且只有一个指针,这个指针就是用来指向下一个节点的,单向链表顾名思义就是链表方向是单方向的,而本文要介绍的双向链表就是链表方向是双方向的,也就是双向链表中的每一个节点有两个指针,一个指针用来指向上一个节点(前驱),另一个指针用指向下一个节点(后继)。

  本文主要是总结一下自己对双向链表的基本操作,当然我也只是写了几个比较简单的操作,其中包括双向链表的创建,插入节点,删除节点,还有输出节点的数据等。学习这个双向链表总的感受就是特别绕,因为涉及多个指针的操作,对于指针没有学好的人儿来说,理解双向链表还是比较困难的。不过功夫不负有心人,只要肯花时间,我觉得一切都不是问题的。下面贴上自己写的代码:

/*********************************************************************************
*      Copyright:  (C) 2017 zoulei
*                  All rights reserved.
*
*       Filename:  link.c
*    Description:  This file
*
*        Version:  1.0.0(2017年07月26日)
*         Author:  zoulei <zoulei121@gmail.com>
*      ChangeLog:  1, Release initial version on "2017年07月26日 18时51分00秒"
*
********************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
typedef struct DoubleLinkNode
{
int data;
struct DoubleLinkNode *prev;
struct DoubleLinkNode *next;
}Node;
/* 创建一个带头节点的双向链表 */
Node*Create_Double_link()
{
Node*head;
Node*pnext;
Node*plast;
int i,n;
head=(Node*)malloc(sizeof(Node));
assert(NULL != head);
head->prev=NULL;
head->next=NULL;

printf("please input the length of the double linked list:");
scanf("%d",&n);
while(n!=0)
{
plast=head;
for(i=0;i<n;i++)
{
pnext=(Node*)malloc(sizeof(Node));
printf("向第%d个节点输入数据:",i+1);
scanf("%d",&pnext->data);
plast->next=pnext;
pnext->prev=plast;
plast=plast->next;
}
pnext->next=NULL;
break;
}
return head;
}
/* 输出每一个节点的数据 */
void print(Node*head)
{
Node*temp;
int j=0;
temp=head;
while(temp->next!=NULL)
{
j++;
printf("输出第%d个节点的数据:%d\n",j,temp->next->data);
temp=temp->next;
}
printf("输出第%d个节点的数据:%p\n",j+1,temp->next);
}
/* 插入节点 */
int InsertNode(Node* head)
{
Node*new;
Node*pnext=head;
int i=0;
int n;

printf("please input the location which is inserted:");
scanf("%d",&n);

while((i<n) && (pnext!=NULL))
{
i++;
pnext=pnext->next;

}
if(pnext==NULL)
{
return 1;
}
else
{
new=(Node*)malloc(sizeof(Node));
printf("请在新插入的节点中输入数据:");
scanf("%d",&new->data);

new->next=pnext->next;
if(n=0)
{
pnext->next=new;
new->next=NULL;
}
else
{
pnext->next=new;
pnext->next->prev=new;
new->prev=pnext;
}
}
return 0;
}
/*删除节点 */
int DeleteNode(Node*head)
{
Node*pnext=head;
Node*ptr;
int n;
int i=0;
printf("please input the node that you will delete:");
scanf("%d",&n);
while((i<n-1) && (pnext!=NULL))
{
i++;
pnext=pnext->next;
}
if(pnext->next->next!=NULL)
{
ptr=pnext->next;
ptr->next->prev=pnext;
pnext=ptr->next;
free(ptr);
}
else
{
ptr=pnext->next;
free(ptr);
}
return 0;
}
/* 主函数 */
int main(int argc,char**argv)
{
Node* head;
head=Create_Double_link();
InsertNode(head);
DeleteNode(head);
print(head);
return 0;
}

代码分析:

1.创建原链表如图所示:





头节点的一个指针初始化时指向NULL,分析一下核心代码吧!plast是我定义的一个临时指针,通过这个临时指针将所有节点连接起来,首先将plast指向头结点,pnext是指向新增节点的指针,所以用plast->next指向新增节点,新增节点的pnext->prev指向前一节点,由于是新增第一个节点,所以第一个节点也就指向头结点,而头节点的head->next指向第一个节点,最后再将临时指针指向第一个节点,这样不断的循环下去,就可以创建指定长度的链表了。不过最后一个节点指向下一个节点的指针必须赋值为为NULL,对应代码就是源文件中的 pnext->next=NULL;

2.在原链表的指定位置插入一个节点,如下图:



这里在原链表的指定位置插入一个节点,整体思想是:先循环遍历到要插入的位置,再把插入的节点的一个指针用来指向下一个节点,即将插入的节点的另一个指针指向上一个节点,不过首先要把插入的那个位置的节点与之相连的下一个节点断开。代码怎么来实现这个逻辑呢?假设以上图为例,我的目的是想在第一个节点与第二个节点之间插入一个新的节点,代码实现是这样的:首先用一个while循环遍历到第一个节点的位置,然后用一个指针pnext指向第一个节点,pnext->next指针就是指向第二个节点,然后new是一个指向新增节点地址的指针,在我们要断开第一个节点与第二个节点之前,用新增节点的指针new->next指向第二个节点的地址,这样后面我们才能操作第二个节点的地址,也就是对应 new->next=pnext->next;这段代码;接着将原先指向第二个节点的指针pnext->next指向新增节点的地址也就是指向new;然后将原先指向第一个节点的指针pnext->next->prev现在改为指向新增节点的地址(new是指向新增节点的内存地址的指针,这里prev指向new也就指向了新增节点的内存地址);最后将新增节点的另一个指针prev指向第一个节点的地址,这样就将第一个节点与第二个节点断开了,同时也将新节点插入到了指定位置。

3.删除原链表中指定的节点,如图所示:



删除指定节点过程也就是插入指定节点的逆过程。看图就明白了,这里就不分析了。

测试结果(只贴上删除节点的):



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: