双向链表的相对于单向链表,更加方便,应因为它指针域里有前面结点的地址。
//
// Created by liujun on 2022/4/16.
//
#include <stdio.h>
#include <stdlib.h>
typedef struct data{
int num; //数据域:存放数据
struct data *prev; //前驱指针:指向前一个节点的地址
struct data *next; //后继指针:指向下一个节点的地址
}Data;
/*
函数功能:
创建一个头节点,并将头节点的地址返回
返回值:
成功:返回一片地址
失败:返回NULL
*/
Data *request_head_node(void)
{
Data *head = (Data *)malloc(sizeof(Data));
if(head == NULL)
{
printf("malloc head fail\n");
return NULL;
}
head->prev = NULL;
head->next = NULL;
return head;
}
/*
函数功能:
传入数据,给这个数据申请一个新节点来存放
参数:
data_num:要存放的数据
返回值:
申请好的新节点的地址
*/
Data *request_new_node(int data_num)
{
Data *new = (Data *)malloc(sizeof(Data));
if(new == NULL)
{
printf("malloc new node fail\n");
return NULL;
}
new->num = data_num;//将传入的数据存放到新节点的数据域
new->prev = NULL;//让前驱指针指向NULL,还没有加入链表
new->next = NULL;//让后继指针指向NULL,还没有加入链表
return new;
}
/*
函数功能:
头插法插入节点,将新节点插入到头节点后一个节点
参数:
head:要被插入的链表的头节点
new:要插入链表的新节点
*/
void inset_to_head(Data *head,Data *new)
{
//先改变要插入的节点的指针域
new->prev = head;
new->next = head->next;
//再改变要插入位置的前后节点的指针域
if(head->next != NULL)//如果只有头节点,就不需要解引用头节点的下一个节点,不然就是解引用NULL
{
head->next->prev = new;
}
head->next = new;
}
/*
函数功能:
打印链表中的所有数据
参数:
head:链表的头节点
*/
void show_list(Data *head)
{
Data *p = NULL;
//因为头节点不存放数据,不用打印头节点内容
for(p=head->next;p!=NULL;p=p->next)
{
printf("%d\t",p->num);
}
printf("\n");
}
/*
函数功能:
将新节点插入到链表尾部
参数:
head:要被插入的链表的头节点
new:要插入的节点
*/
void inset_to_last(Data *head,Data *new)
{
//找到尾节点
Data *p = NULL;
for(p=head;p->next!=NULL;p=p->next);
//将新节点插入到尾节点后面
new->prev = p;
p->next = new;
}
/*
函数功能:
根据传入的数据来查找存放了这个数据的节点
参数:
head:链表头节点
find_num:要查找的数据
返回值:
成功:返回找到的节点
失败:返回NULL
*/
Data *find_node(Data *head,int find_num)
{
Data *p = NULL;
for(p=head->next;p!=NULL&&p->num!=find_num;p=p->next);//查找节点
return p;
}
/*
函数功能:
根据传入的数据,删除对应的节点
参数:
head:链表头节点
delete_num:要删除的节点里的数据
返回值:
成功:返回0
失败:返回-1
*/
int delete_node(Data *head,int delete_num)
{
Data *p = find_node(head,delete_num);
if(p != NULL)//p不为NULL就说明p就是要删除的节点
{
Data *prev = p->prev;//用prev记录下p的前一个节点
prev->next = p->next;//让p前一个节点的后继指针指向p的后面
if(p->next != NULL)//如果p不是最后一个节点,说明它后面还有节点
{
p->next->prev = prev;//让p的后一个节点的前驱指针指向p的前一个节点
}//p就被脱离出了链表
p->prev = NULL;//保险起见,清空脱离节点的指针域
p->next = NULL;
free(p);
return 0;
}
return -1;
}
/*
函数功能:
删除一条链表
参数:
head:要删除的链表的头节点
*/
void remove_list(Data *head)
{
Data *p = NULL;//指向要删除的节点
for(p=head->next;head->next!=NULL;p=p->next)
{
//让头节点的下一个指向要删除节点的下一个
head->next = p->next;
free(p);
}
//循环结束,只剩一个头节点,再头节点释放
free(head);
}
int main(int argc, char const *argv[])
{
//申请链表的头节点
Data *head = request_head_node();
Data *new = NULL;
int n;
while(1)
{
scanf("%d",&n);
if(n == 0)
{
break;
}
if(n > 0)
{
new = request_new_node(n);
inset_to_last(head,new);
}
if(n < 0)
{
delete_node(head,0-n);
}
/*
if(n < 0)
{
Data *find = find_node(head,0-n);
if(find != NULL)
{
printf("find node is %d\n",find->num);
}
else
printf("没有这个节点\n");
}
*/
show_list(head);
}
remove_list(head);
return 0;
}