//双向动态链表
#include <stdio.h>
#include <stdlib.h>
/** 链表结点中存储的数据的类型:LNodeT **/
typedef int LNodeT;
/** 链表结点的数据类型的预先声明 **/
struct linklist;
/** 单向链表结点的数据类型,两部分:data为数据、next为下一结点的地址(链接结构),pre为上一个结点的地址 **/
struct linklist {
LNodeT data;
struct linklist *next;
struct linklist *pre;/** 双向链表的结点还要多一个向前的指针**/
};
/** 单向链表结点中存储的数据的类型:LNodeT **/
typedef struct linklist LinkT;
/** 动态申请存储空间,创建链表的结点 **/
LinkT* creat_node(LNodeT a)//已测试
{
//开辟空间
LinkT *p=(LinkT*)malloc(sizeof(LinkT));
if(!p)
{
printf("在开辟空间时出现错误!");
exit(0);
}
//数据域初绐化
p->data=a;
//指针域初绐化
p->next=NULL;
p->pre=NULL;
return p;
}
/** 释放链表结点的存储空间 **/
void erase_node(LinkT *p)//已测试
{
free(p);
}
#define erase_node(p) (free(p))//已测试
/** 在链表头部插入一个结点,返回头结点指针 **/
LinkT* insert_first1(LinkT *head, LNodeT a)
{
LinkT *p=creat_node(a);
LinkT* insert_first(LinkT *head, LinkT *p);
return insert_first(head,p);
}
/** 在链表头部插入一个结点,返回头结点指针 **/
LinkT* insert_first(LinkT *head, LinkT *p)//已测试
{
if(!head)
{
//此时p的指针,head只要旨向p就可以了
p->next=p;
p->pre=p;
head=p;
}
else
{
//p的前指针指向head指向结点的前一个结点
p->pre=head->pre;
//p的后指针指向head指向的结点
p->next=head;
//head指向结点的前一个结点的后指针指向p
head->pre->next=p;
//head指向结点的前指针指向p
head->pre=p;
//head指向新开辟的这个结点
head=p;
}
return head;
}
/** 在链表尾部插入一个结点 **/
LinkT* insert_tail(LinkT *head, LinkT *p)//已测试
{
if(!head) return insert_first(head, p);
//在尾部插入相当于在第一个位置插入后head后移一个位置
head=insert_first(head, p);
return head->next;
}
/** 依照结点的数据内容,在链表中插入一个结点 **/
LinkT* insert_by_data(LinkT *head,LNodeT node)//已测试
{
//首先要给这个等插入的数据开辟一个空间
LinkT *p=head,*link=creat_node(node);
//针对链表空否进行插入
if(!p)//如果这个链表是一个空的,则这个结点要插头部
{
head=insert_first(head,link);
return head;
}
else//如果这个链表不为空,但是这个链表的第一项就符合要求,则要插在首结点后面
{
//针对第一个是不是要插入的位置进行分析
if(p->data==node)//是
{
head=insert_first(head,link);
return head;
}
else//不是
{
//否则的话,要先遍历这个链表,找到要插入的位置
p=head->next;
while(p!=head && p->data!=node)//如果这个链表没有这么样子的结点,或者是找到了插入的位置,则退出循环
{
p=p->next;
}
//插入这个结点
insert_first(p,link);
}
return head;
}
}
/** 依照结点的顺序,在链表中插入一个结点 **/
LinkT* insert_by_sub(LinkT *head,int n,LinkT *link)//已测试
{
int i;
LinkT *p;
if(n<=0)
{
printf("插入位置有误!/n");
return head;
}
else
{
//对插入位置是不是第一个做出判断
if(n==1)
{
insert_first(head,link);
}
else
{
i=1;
p=head->next;
//找到插入位置,并且用p指向它,如果没有找到的话就插在未尾
while(p!=head && i!=n)
{
p=p->next;
i++;
}
insert_first(p->pre,link);
}
return head;
}
}
/** 在链表头部删除一个结点 **/
LinkT* delete_first(LinkT *head)//已测试
{
LinkT *link;
//链表有可能为空
if(!head) return NULL;
//如果这个链表是一个只有一个结点的链表,那么处理如下
if(head==head->next)
{
erase_node(head);
return NULL;
}
/*其它的情况处理如下*/
//记录下头结点的下一个结点
link=head->next;
//head指向前一个结点的后指针指向link
head->pre->next=link;
//link的前指针指向head的前一个结点
link->pre=head->pre;
//释放head指向的节点
erase_node(head);
//head指向新链表的第一个结点
head=link;
return head;
}
/** 在链表尾部删除一个结点 **/
LinkT* delete_tail(LinkT *head)//已测试
{
/*如果这个链表是一个空的链表的话*/
if(!head) return NULL;
/*不为空的话,处理如下*/
//在尾啊del一个结点相当于把原链表head->pre当做头结点del第一个结点
head=delete_first(head->pre);
return head;
}
/** 依照结点的数据内容,在链表中删除一个结点 **/
LinkT* delete_by_data(LinkT *head,LNodeT node)//已测试
{
//第一步关于head的后移问题,即 head指向的就是要删除的
LinkT *p=head;
if(!head) return NULL;
while(head->data==node)
{
head=delete_first(head);
}
//删除完成后head可能变成一个空的指针
if(!head) return head;
//第二步关于删除和node相同的结点
p=head->next;
while(p!=head)
{
if(p->data==node)
{
//在这个过程式中p已经后移
p=delete_first(p);
}
else
{
p=p->next;
}
}
return head;
}
/** 依照结点的顺序,在链表中删除一个结点 **/
LinkT* delete_by_sub(LinkT *head,int n)//已测试
{
int i;
LinkT *p;
if(n<=0)
{
printf("删除位置有误!/n");
return head;
}
else
{
//对删除位置是不是第一个做出判断
if(n==1)
{
head=delete_first(head);
}
else
{
i=1;
p=head->next;
//找到删除位置,并且用p指向它
while(p!=head && i!=n)
{
p=p->next;
i++;
}
if(p!=head || i==n)//i==n是为了看看最后一个是不是要删的
{
p=p->pre;
delete_first(p);
}
}
return head;
}
}
/** 取链表的长度(结点数) **/
size_t linklen(LinkT *head)//已测试
{
size_t num=0;
LinkT *p;
if(!head) return 0;
p=head->next;
num=1;
while(p!=head)
{
num++;
p=p->next;
}
return num;
}
/** 依照结点的数据内容,遍历链表 **/
LinkT* travel_by_data(LinkT *head,LNodeT node,void (*travel)(LNodeT a))//已测试
{
//处理开始部分
LinkT *p=head;
if(p->data==node)
{
(*travel)(head->data);
}
//处理其它部分
p=head->next;
while(p!=head)
{
if(p->data==node)
{
(*travel)(p->data);
}
p=p->next;
}
return head;
}
/** 依照结点的顺序,遍历链表 **/
LinkT* travel_by_seq(LinkT* head,void (*travel)(LNodeT a))//已测试
{
LinkT *p;
if(!head) return NULL;
(*travel)(head->data);
p=head->next;
while(p!=head)
{
(*travel)(p->data);
p=p->next;
}
return head;
}