在写这个代码的实现之前我们先来了解下相关的知识。
首先,带头结点带环的双向链表的特点:
带头节点:创建一个结点表示空链表,这个节点就是头结点,并且头结点中的数据不具有实际的意义。但是我们一般不关心头结点中的元素,只起“带头”作用。双向要求每个结点中都有一个next指针指向下一个,一个prev指针指向下一个。
1、双向链表的数据结构
双向的带头结点的带环的链表有三个成员,一个是数据,一个是指针next指向的是当前节点的下一个结点,还有一个是指针prev指向的是当前节点的前一个节点,即每个结点都有一个直接的前驱,一个直接的后继。
typedef char DLinkType;
typedef struct DLinkNode {
DLinkType data;
struct DLinkNode* next;
struct DLinkNode* prev;
} DLinkNode;
2、双向链表的初始化
双向链表的初始化就是用一个傀儡结点代表其为空,这里将头结点的数据初始化为0,注意,双向链表当中没有没有空指针,所以将双向链表的头结点的next指向的是它自己,将双向链表的prev指向的也是自己,即判断一个双向带头结点的链表是否为空的条件就是head->next==head;head->prev==head.
DLinkNode* creatnode(DLinkType value){
//创建新节点
DLinkNode* newnode = (DLinkNode*)malloc(sizeof(DLinkNode));
if (newnode == NULL){
return;
}
newnode->data = value;
newnode->prev = NULL;
newnode->next = NULL;
}
void DLinkListInit(DLinkNode** head){
if (*head == NULL){
return;//非法输入
}
*head = creatnode(0);
(*head)->prev = *head;
(*head)->next = *head;
}
3、创建一个新的结点
既然我们要对链表进行插入数据,那便需要对其创建一个指定数据的节点,然后我们再将其插入链表当中。创建节点就是先对其进行分配空间,再将节点对应数据改为我们需要的目标数据。
DLinkNode* creatnode(DLinkType value){
//创建新节点
DLinkNode* newnode = (DLinkNode*)malloc(sizeof(DLinkNode));
if (newnode == NULL){
return;
}
newnode->data = value;
newnode->prev = NULL;
newnode->next = NULL;
}
4、我们对双向链表的尾插
也是采用的是先创建一个新的结点,然后定义一个prev指针指向头结点的下一个结点,然后我们去修改prev和新创建的新节点的指向。
DLinkNode* DLinkListPushBack(DLinkNode* head, DLinkType value)
{
if (head == NULL){
return;
}
DLinkNode* newnode = creatnode(value);
DLinkNode* tail = head->prev;
//head和newnode
head->prev = newnode;
newnode->next = head;
//tail和newnode
tail->next = newnode;
newnode->prev = tail;
}
5、对元素进行尾删
void DLinkListPopBack(DLinkNode* head){
53 if(head==NULL){
54 return ;
55 }
56 if(head->next==head ||head->prev==head){
57 //空链表
58 return ;
59 }
60 DLinkNode* to_delete=head->prev;
61 DLinkNode* cur=to_delete->prev;
62 cur->next=head;
63 head->prev=cur;
64 DLinkListDestroy(to_delete);
65 }
66
6、进行头插
void DLinkListPushFront(DLinkNode* head, DLinkType value)
69 {
70 if(head==NULL){
71 return;
72 }
73 DLinkNode* newnode=creatnode(value);
74
75 DLinkNode* cur=head->next;
76 //head和newnode
77 head->next=newnode;
78 newnode->prev=head;
79 //new和cur
80 newnode->next=cur;
81 cur->prev=newnode;
82 }
83
7、进行头删
83
84 void DLinkListPopFront(DLinkNode* head)
85 {
86 if(head==NULL){
87 return;
88 }
89 if(head->next== head || head->prev==head){
90 //空链表
91 return;
92 }
93 DLinkNode* to_delete=head->next;
94 DLinkNode*tmp=to_delete->next;
95 head->next=tmp;
96 tmp->prev=head;
97 DLinkListDestroy(to_delete);
98 }
8、找到指定的元素
DLinkNode* DLinkListFind(DLinkNode* head, DLinkType to_find)
{
if (head == NULL){
return NULL;
}
DLinkNode* cur = head->next;
for (; cur != head; cur = cur->next){
if (cur->data == to_find){
return cur;
}
}
return NULL;
}
9、指定位置之前进行插入元素
//往指定位置之前插入一个元素
void DLinkListInsert(DLinkNode* head, DLinkNode* pos, DLinkType value){
if (head == NULL || pos == NULL){
return;//非法输入
}
DLinkNode* cur = pos->prev;
DLinkNode* newnode = creatnode(value);
//pos->prev和newnode
cur->next = newnode;
newnode->prev = cur;
//newnode和pos
newnode->next = pos;
pos->prev = newnode;
}
10、指定位置之后进行元素的插入
//往指定位置之后插入一个元素
void DLinkListInsertAfter(DLinkNode* head, DLinkNode* pos, DLinkType value){
if (head == NULL || pos == NULL){
return;
}
DLinkNode* cur = pos->next;
DLinkNode* newnode = creatnode(value);
//pos->next和newnode
cur->prev = newnode;
newnode->next = cur;
//newnode和pos
pos->next = newnode;
newnode->prev = pos;
}
11、删除指定位置的元素
void DLinkListErase(DLinkNode* head, DLinkNode* to_delete){
//删除指定位置的元素
if (head == NULL){
return;
}
DLinkNode* pro = to_delete->prev;
DLinkNode* pre = to_delete->next;
pro->next = pre;
pre->prev = pro;
DLinkListDestroy(to_delete);
}
12、删除指定值元素,只删除一个
void DLinkListRemove(DLinkNode* head, DLinkType to_delete)
//删除指定值元素
{
if (head == NULL){
return;
}
if (head->next == head){
return;
}
DLinkNode* ret = DLinkListFind(head, to_delete);
DLinkListErase(head, ret);//这里只是删除,而不是进行销毁结点
}
13、删除指定值出现的所有的值(将所有的指定值都进行删除
)
void DLinkListRemoveAll(DLinkNode* head, DLinkType to_delete){
if (head == NULL){
return;
}
if (head->next == head){
return;
}
while (1){
DLinkNode* ret = DLinkListFind(head, to_delete);
if (ret == NULL){
break;
}
DLinkListErase(head,ret );
}
}
14、求双向链表的长度
size_t DLinkListSize(DLinkNode* head)
{
if (head == NULL){
return;
}
DLinkNode* cur = head->next;
int i = 0;
while (cur!= head){//注意在这里我们必须写成cur而不是写成head->next
i++;
cur = cur->next;
}
return i;
}
15、我们判断链表是否为空
int DLinkListEmpty(DLinkNode* head){
if (head == NULL){
return;
}
if (head->next!= head){
return 1;
}
return 0;
}