//带头结点的双向链表
#pragma once
typedef char DataType;
typedef struct Node
{
DataType data; //数据区
struct Node *next; //指向下一个节点
struct Node *pre; //指向前一个节点
}DLinklistNode;
//创建一个新节点
DLinklistNode* DLinklistCreatNode(DataType value)
{
DLinklistNode* newnode=(DLinklistNode *)malloc(sizeof(DLinklistNode));
newnode->next=newnode;
newnode->pre=newnode;
newnode->data=value;
return newnode;
}
初始化
void DLinklistInit(DLinklistNode** phead)
{
if( phead==NULL)
{
printf( " 非法输入\n");
return ;
}
*phead=DLinklistCreatNode('0');
}
//打印链表
void DLinklistPrint(DLinklistNode *phead,char* s)
{
if( phead==NULL)
{
printf( " 非法输入\n");
return ;
}
printf("\n%s\n",s);
//打印头结点
//printf("[%c][%p]\n",phead->data,phead);
//从头到尾打印
DLinklistNode *cur1=phead->next;
while(cur1!=phead)
{
printf("[%c][%p] ",cur1->data,cur1);
cur1=cur1->next;
}
printf("\n");
//从尾到头打印
DLinklistNode *cur2=phead->pre;
while(cur2!=phead)
{
printf( "[%c][%p] ",cur2->data,cur2);
cur2=cur2->pre;
}
//打印头结点
// printf("[%c][%p] ", cur2 -> data, cur2 -> pre);
}
//尾插
void DLinklistPushBack(DLinklistNode* phead,DataType value)
{
if( phead==NULL)
{
printf( " 非法输入\n");
return ;
}
//创建一个新节点
DLinklistNode *newnode=DLinklistCreatNode(value);
//定义一个尾节点
DLinklistNode* tail=phead->pre;
//phead vs newnode
newnode->next=phead;
phead->pre=newnode;
//tail vs newnode
newnode->pre=tail;
tail->next=newnode;
}
//销毁一个节点
void DLinklistDestory(DLinklistNode* to_delete)
{
if(to_delete==NULL)
{
printf( "非法操作\n");
return;
}
free(to_delete);
}
//尾删
void DLinklistPopBack(DLinklistNode* phead)
{
if( phead==NULL)
{
printf( " 非法输入\n");
return ;
}
if( phead->next==NULL)
{
printf( "空链表\n");
return;
}
//找到删除节点和删除节点的前一个节点
DLinklistNode* to_delete=phead->pre;
DLinklistNode* pre_delete=to_delete->pre;
//phead vs pre_delete
pre_delete->next=phead;
phead->pre=pre_delete;
//释放to_delete
DLinklistDestory(to_delete);
}
//头插
void DLinklistPushFront(DLinklistNode* phead,DataType value)
{
if(phead==NULL)
{
printf("非法输入\n");
return ;
}
//创建新节点
DLinklistNode* newnode=DLinklistCreatNode(value);
//找到头结点之后的第一个节点
DLinklistNode* after=phead->next;
//newnode vs head
newnode->pre=phead;
phead->next=newnode;
//newnode vs after
newnode->next=after;
after->pre=newnode;
}
//头删
void DLinklistPopFront( DLinklistNode* phead)
{
if( phead==NULL)
{
printf( " 非法输入\n");
return ;
}
if( phead->next==NULL)
{
printf( "空链表\n");
return;
}
//找到删除节点和删除节点的后一个节点
DLinklistNode* to_delete=phead->pre;
DLinklistNode* to_delete_next=to_delete->next;
//修改指向
phead->next=to_delete_next;
to_delete_next->pre=phead;
//释放节点
DLinklistDestory(to_delete);
}
//查找指定值的位置
DLinklistNode* DLinklistFind(DLinklistNode* phead,DataType to_find)
{
if( phead==NULL)
{
printf( " 非法输入\n");
return ;
}
//空链表,返回NULL
if( phead->next==NULL)
{
printf( "空链表\n");
return NULL;
}
//定义一个指针遍历链表,找到返回cur指针
DLinklistNode* cur=phead->next;
while(cur!=phead)
{
if( cur->data==to_find)
{
return cur;
}
cur=cur->next;
}
//找不到,返回NULL
return NULL;
}
在任意位置之后插入
void DLinklistInsert(DLinklistNode* phead,DLinklistNode*pos,DataType value)
{
if(phead==NULL||pos==NULL)
{
printf( " 非法输入\n");
return ;
}
//创建一个节点
DLinklistNode* newnode=DLinklistCreatNode(value);
//找到pos之前的节点
DLinklistNode* cur=pos->pre;
//newnode vs cur
cur->next=newnode;
newnode->pre=cur;
//newnode vs pos
newnode->next=pos;
pos->pre=newnode;
}
在任意位置之后插入
void DLinklistInsert_Front(DLinklistNode* phead,DLinklistNode*pos,DataType value)
{
if(phead==NULL||pos==NULL)
{
printf( " 非法输入\n");
return ;
}
//创建一个节点
DLinklistNode* newnode=DLinklistCreatNode(value);
//找到pos之前的节点
DLinklistNode* cur=pos->next;
//newnode vs pos
pos->pre=newnode;
newnode->next=pos;
//newnode vs cur
newnode->pre=cur;
cur->next=newnode;
}
//删除指定位置的值
void DLinkListErase(DLinklistNode* phead,DLinklistNode* pos)
{
if(phead==NULL||pos==NULL)
{
printf( " 非法输入\n");
return ;
}
if( phead->next==NULL)
{
printf( "空链表\n");
return NULL;
}
//找到pos之前和之后的节点
DLinklistNode* before=pos->pre;
DLinklistNode* after=pos->next;
//before vs after
before->next=after;
after->pre=before;
}
//删除指定值
void DLinkListRemove(DLinklistNode* phead,DataType value)
{
if(phead==NULL||pos==NULL)
{
printf( " 非法输入\n");
return ;
}
//定一个节点,遍历链表
DLinklistNode* cur=phead->next;
for(;cur!=phead;cur=cur->next)
{
//找到链表中的第一个value值,
if( cur->data==value)
{
//保存存放value值的节点
DLinklistNode* tmp=cur;
//修改tmp节点前节点和后节点指向关系
cur->pre->next=cur->next;
cur->next->pre=cur->pre;
//销毁tmp节点
DLinklistDestory(tmp);
返回
return ;
}
}
}
//删除指定值的所有元素
void DLinkListRemoveAll(DLinklistNode* phead,DataType value)
{
if(phead==NULL||pos==NULL)
{
printf( " 非法输入\n");
return ;
}
DLinklistNode* cur=phead->next;
//遍历链表,找到所有value值,并删除
for(;cur!=phead;cur=cur->next)
{
if( cur->data==value)
{
DLinklistNode* tmp=cur;
cur->pre->next=cur->next;
cur->next->pre=cur->pre;
DLinklistDestory(tmp);
}
}
}
//求双向链表的长度
size_t DLinkListSize(DLinklistNode* phead)
{
if(phead==NULL||pos==NULL)
{
printf( " 非法输入\n");
return ;
}
//定义一个指针遍历链表,一个计数器计数
DLinklistNode* cur=phead->next;
size_t count=0;
for( ;cur!=phead;cur=cue->next)
{
++count;
}
return count;
}
//判断链表是否为空
int DLinkListEmpty(DLinklistNode* phead)
{
//链表为空,返回0,不为空返回1,非法操作返回-1
if(phead==NULL||pos==NULL)
{
printf( " 非法输入\n");
return -1;
}
if(phead->next==NULL)
{
return 0;
}
return 1;
}
总结:
在对链表进行插入删除等操作之前一定要对链表进行初始化,否则就会出现段错误,或者重复插入的情况。
在任意位置插入之前,首先的找到插入位置,这个时候可以将未知问题化为已知问题。先调用查找函数,然后进行插入操作。
各个节点的关系要确认清楚,尤其在任意位置之前插入和任意位置之后插入。