嘿,(≧▽≦)/ 前几天在书上看见了双向链表,就学了一下,哈哈哈(〜^㉨^)〜
顾名思义,双向链表每个结点有两个指针域,一个指向前驱节点,一个指向后继结点。
但是双向链表在创建,插入,和删除操作上略有不同。例如在插入和删除时,不必像单链表一样只能在目标的前驱结点上操作
(觉得它能实现查询数据时上一个,下一个的功能哦!!)
下面只是我的一些想法,可能很菜啊 ╮( ̄▽ ̄")╭;
结点定义如下:
typedef struct Node
{
int data;
struct Node *prior; //指向前驱
struct Node *next; //指向后继
}Node,*pNode; //这里 pNode 等价于 Node* 是指向结点的指针
函数声明如下:
pNode creat(int n); //创建双向链表
void output(pNode h); //打印双向链表
int if_empty(pNode); //判空
int length(pNode h); //返回链表长度
void Insert(pNode h,int i,int data); //插入
void Delete(pNode h,int i); //删除
各项功能的函数定义如下:
(1)创建双链表
pNode creat(int n) //创建链表
{
int i;
pNode h,p,r;
h=r=(pNode)malloc(sizeof(Node));//其中h是头指针,r是尾指针
if(h==NULL) //内存分配失败
exit(-1);
h->prior=h->next=NULL; //将头节点的两个指针域都指向NULL
printf("输入数据:");
for(i=0; i<n; i++)
{
p=(pNode)malloc(sizeof(Node));
if(h==NULL) //内存分配失败
exit(-1);
scanf("%d",&p->data);
p->next=NULL;
r->next=p;
p->prior=r;
r=r->next;
}
return h;
}
双向链表的创建我采用的是尾插法,因为如果是头插法则会有两种情况,1是在头结点和NULL之间插,2是在头结点与其后结点之间插,稍微麻烦一点点。而尾插法只需插在尾结点和NULL之间。在文章最后我附上了双向链表的头插法。
(2)打印链表,判空,返回链表长度
void output(pNode h) //打印链表
{
pNode p=h->next;
printf("打印链表:");
while(p)
{
printf("%d ",p->data);
p=p->next;
}
}
int empty(pNode h) //判断链表是否为空
{
pNode p=h->next;
if(p==NULL)
return 1;
else
return 0;
}
int length(pNode h) //返回链表长度
{
int length=0;
pNode p=h->next;
while(p)
{
length++;
p=p->next;
}
return length;
}
void Insert(pNode h,int i,int data) //插入 1<=i<=length+1
{
pNode p,r;
p=r=h;
int j=0;
if(i==length(h)+1) //当插入的位置为length+1时
{
pNode q=(pNode)malloc(sizeof(Node));
q->data=data;
q->next=NULL;
while(r->next) //找到链表尾结点
r=r->next;
r->next=q;
q->prior=r;
}
else
{
while(p&&(j<i)) //找到第i个结点的
{
p=p->next;
j++;
}
if(!p||(j>i))
exit(-1);
pNode q=(pNode)malloc(sizeof(Node));
q->data=data;
//插入的核心步骤
q->prior=p->prior;
p->prior->next=q;
q->next=p;
p->prior=q;
//
}
}
1.插入有两种情况,一是在两结点之间,另外一个是最后一个节点与NULL之间。
2.对于两节点之间插入的情况,指针p指向了其中一个节点,则新结点先与另一个结点连接,之后再与该结点连接。因为指针p已经记录了该结点的位置,不用担心指向它的指针域被覆盖。
(3)删除操作
void Delete(pNode h,int i) //删除
{
pNode p=h;
int j=0;
while(p&&(j<i)) //找到删除结点
{
p=p->next;
j++;
}
if(p->next==NULL)
p->prior->next=NULL;
else
{
p->prior->next=p->next;
p->next->prior=p->prior;
}
free(p);
}
删除操作有p->next==NULL和p->next!=NULL两种情况
用于测试的主函数
int main()
{
int n,i,data;
pNode head;
printf("输入输入数据个数");
scanf("%d",&n);
head=creat(n);
output(head);
printf("
输入插入 位置i 和 数据data :
");
scanf("%d",&i);
scanf("%d",&data);
Insert(head,i,data);
output(head);
printf("
要删除第几个数据");
scanf("%d",&i);
Delete(head,i);
output(head);
return 0;
}
(≧▽≦)/(≧▽≦)/(≧▽≦)/(≧▽≦)/(≧▽≦)/(≧▽≦)/~~~~~~先结束了。
附录
双向链表的头插法
pNode creat(int n)
{
int i;
pNode h,p;
h=(pNode)malloc(sizeof(Node));
if(h==NULL)
exit(-1);
h->prior=h->next=NULL;
printf("输入数据:");
p=(pNode)malloc(sizeof(Node));
if(h==NULL)
exit(-1);
scanf("%d",&p->data);
h->next=p;
p->prior=h;
p->next=NULL;
for(i=1; i<n; i++)
{
p=(pNode)malloc(sizeof(Node));
if(h==NULL)
exit(-1);
scanf("%d",&p->data);
p->next=h->next;
h->next->prior=p;
h->next=p;
p->prior=h;
}
return h;
}