具体函数操作如下:
(1)动态申请节点
DCListNode* BuyDCListNode(DLDataType x)// 动态申请节点
{
DCListNode* newNode = (DCListNode*)malloc(sizeof(DCListNode));
if (NULL == newNode)
{
assert(0);
return NULL;
}
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
(2)初始化
申请好头节点,头节点的前驱和后继都指向自己
DCListNode* DCListInit()// 初始化
{
//只需要申请好头节点
DCListNode* head = BuyDCListNode(0);
head->next = head;
head->prev = head;
return head;
}
(3)将有效节点都清除
这里采取头删的方法清除有效节点,头删方法的具体实现下面会仔细解释。在对双向链表进行遍历时,需要对指针加以限定,否则会进入无限循环的状态,判断循环指针是否等于头节点即可。
清除有效节点后,元素为空,所以需要将头指针的前驱和后继指向自己。
void DCListClear(DCListNode* pHead)// 将有效节点清除
{
assert(pHead);
DCListNode* tail = pHead->next;
while (tail != pHead)
{
//采用头删的方法
pHead->next = tail->next;
free(tail);
tail = pHead->next;
}
//链表为空
pHead->next = pHead;
pHead->prev = pHead;
}
(4)销毁
在进行销毁操作时,需要将头节点和有效节点都进行清除,调用清除的函数,然后将头节点进行删除设置为空,避免成为野指针。
void DCListDestory(DCListNode** pHead)// 双向链表销毁 头节点和有效节点都需要进行清除
{
assert(pHead);
DCListClear(*pHead);
free(*pHead);
*pHead = NULL;
}
(5)双向链表的打印
void DCListPrint(DCListNode* head)// 双向链表打印
{
DCListNode* tail = head->next;
while (tail != head)
{
printf("%d ", tail->data);
tail = tail->next;
}
printf("\n");
}
(6)双向链表的长度
完成链表的遍历后,使用count进行计数,则可得到链表的长度
int DCListSize(DCListNode* pHead) //双向链表长度
{
assert(pHead);
DCListNode* tail = pHead->next;
int count = 0;
while (tail != pHead)
{
++count;
tail = tail->next;
}
return count;
}
(7)判空
链表为空,则头指针指向自身
int DCListEmpty(DCListNode* pHead) //判断是否为空
{
assert(pHead);
return pHead->next == pHead;
}
(8)查找
DCListNode* DCListFind(DCListNode* pHead, DLDataType x)// 双向链表查找
{
assert(pHead);
DCListNode* tail = pHead->next;
while (tail != pHead)
{
if (x == tail->data)
return tail;
tail = tail->next;
}
return NULL;
}
(9)在pos位置插入新节点
双向链表不存在插入pos位置之后还是之前的问题,所以这里我们选择插入pos位置之前。
①先不要断开原来的链表,先将新节点连接在原链表中
②断开原链表,插入新节点,让对应节点的指针域指向新插入的节点
void DCListInsert(DCListNode* pos, DLDataType x)// 双向链表在pos的前面进行插入
{
if (NULL == pos)
return;
DCListNode* newNode = BuyDCListNode(x);
//1.先将新节点连接在原链表中
newNode->next = pos;
newNode->prev = pos->prev;
//2.断开原链表,插入新节点
newNode->prev->next = newNode;
pos->prev = newNode;
}
void DCListErase(DCListNode* pos)// 双向链表删除pos位置的节点
{
if (NULL == pos)
return;
pos->prev->next = pos->prev;
pos->next->prev = pos->prev;
free(pos);
}
(11)尾插
实现尾插操作时,可以直接调用插入元素函数,头节点即是pos位置
void DCListPushBack(DCListNode* pHead, DLDataType x)// 双向链表尾插
{
assert(pHead);
DCListInsert(pHead, x);
}
(12)尾删
在进行尾删操作时,调用任意位置删除函数,pos位置是pHead->prev,即可完成删除操作
void DCListPopBack(DCListNode* pHead)// 双向链表尾删
{
if (DCListEmpty(pHead))
return;
DCListErase(pHead->prev);
}
(13)头插
实现头插操作时,调用插入元素的函数,pos位置为pHead->next 即可实现头插操作
void DCListPushFront(DCListNode* pHead, DLDataType x)// 双向链表头插
{
assert(pHead);
DCListInsert(pHead->next, x);
}
(14)头删
在进行头删操作时,调用任意位置删除函数,pos位置是pHead->next,即可完成删除操作
void DCListPopFront(DCListNode* pHead)// 双向链表头删
{
if (DCListEmpty(pHead))
return;
DCListErase(pHead->next);
}
这次依然将主要的代码分成了三个源文件,DCList.c,test.c,DCList.h,其中DCList.c实现代码中的各个函数,test.c实现顺序表的相关测试,DCList.h实现用到的各种头文件与函数声明。
DCList.h
#pragma once
typedef int DLDataType;
typedef struct DCListNode
{
DLDataType data;
struct DCListNode* next;//指向当前节点的下一个节点
struct DCListNode* prev;//指向当前节点的前一个结点
}DCListNode;
DCListNode* BuyDCListNode(DLDataType x);// 动态申请节点
DCListNode* DCListInit();// 创建返回链表的头结点
void DCListClear(DCListNode* pHead);// 将有效节点清除
void DCListDestory(DCListNode** pHead);// 双向链表销毁
void DCListPrint(DCListNode* pHead);// 双向链表打印
int DCListSize(DCListNode* pHead); //双向链表长度
void DCListPushBack(DCListNode* pHead, DLDataType x);// 双向链表尾插
void DCListPopBack(DCListNode* pHead);// 双向链表尾删
void DCListPushFront(DCListNode* pHead, DLDataType x);// 双向链表头插
void DCListPopFront(DCListNode* pHead);// 双向链表头删
DCListNode* DCListFind(DCListNode* pHead, DLDataType x);// 双向链表查找
void DCListInsert(DCListNode* pos, DLDataType x);// 双向链表在pos的前面进行插入
void DCListErase(DCListNode* pos);// 双向链表删除pos位置的节点
DCList.c
#include "DCList.h"
#include
#include
#include
DCListNode* BuyDCListNode(DLDataType x)// 动态申请节点
{
DCListNode* newNode = (DCListNode*)malloc(sizeof(DCListNode));
if (NULL == newNode)
{
assert(0);
return NULL;
}
newNode->data = x;
newNode->next = NULL;
newNode->prev = NULL;
return newNode;
}
DCListNode* DCListInit()// 初始化
{
//只需要申请好头节点
DCListNode* head = BuyDCListNode(0);
head->next = head;
head->prev = head;
return head;
}
void DCListClear(DCListNode* pHead)// 将有效节点清除
{
assert(pHead);
DCListNode* tail = pHead->next;
while (tail != pHead)
{
//采用头删的方法
pHead->next = tail->next;
free(tail);
tail = pHead->next;
}
//链表为空
pHead->next = pHead;
pHead->prev = pHead;
}
void DCListDestory(DCListNode** pHead)// 双向链表销毁 头节点和有效节点都需要进行清除
{
assert(pHead);
DCListClear(*pHead);
free(*pHead);
*pHead = NULL;
}
void DCListPrint(DCListNode* head)// 双向链表打印
{
DCListNode* tail = head->next;
while (tail != head)
{
printf("%d ", tail->data);
tail = tail->next;
}
printf("\n");
}
int DCListSize(DCListNode* pHead) //双向链表长度
{
assert(pHead);
DCListNode* tail = pHead->next;
int count = 0;
while (tail != pHead)
{
++count;
tail = tail->next;
}
return count;
}
int DCListEmpty(DCListNode* pHead) //判断是否为空
{
assert(pHead);
return pHead->next == pHead;
}
void DCListPushBack(DCListNode* pHead, DLDataType x)// 双向链表尾插
{
assert(pHead);
DCListInsert(pHead, x);
}
void DCListPopBack(DCListNode* pHead)// 双向链表尾删
{
if (DCListEmpty(pHead))
return;
DCListErase(pHead->prev);
}
void DCListPushFront(DCListNode* pHead, DLDataType x)// 双向链表头插
{
assert(pHead);
DCListInsert(pHead->next, x);
}
void DCListPopFront(DCListNode* pHead)// 双向链表头删
{
if (DCListEmpty(pHead))
return;
DCListErase(pHead->next);
}
DCListNode* DCListFind(DCListNode* pHead, DLDataType x)// 双向链表查找
{
assert(pHead);
DCListNode* tail = pHead->next;
while (tail != pHead)
{
if (x == tail->data)
return tail;
tail = tail->next;
}
return NULL;
}
void DCListInsert(DCListNode* pos, DLDataType x)// 双向链表在pos的前面进行插入
{
if (NULL == pos)
return;
DCListNode* newNode = BuyDCListNode(x);
//1.先将新节点连接在原链表中
newNode->next = pos;
newNode->prev = pos->prev;
//2.断开原链表,插入新节点
newNode->prev->next = newNode;
pos->prev = newNode;
}
void DCListErase(DCListNode* pos)// 双向链表删除pos位置的节点
{
if (NULL == pos)
return;
pos->prev->next = pos->prev;
pos->next->prev = pos->prev;
free(pos);
}
test.c
#include "DCList.h"
int main()
{
DCListNode* head = DCListInit();
DCListPushBack(head, 1);
DCListPushBack(head, 2);
DCListPushBack(head, 3);
DCListPushBack(head, 4);
DCListPushBack(head, 5);
DCListPrint(head);
DCListPushFront(head, 0);
DCListPrint(head);
DCListPopBack(head);
DCListPopFront(head);
DCListPrint(head);
DCListInsert(DCListFind(head, 3), 10);
DCListPrint(head);
DCListErase(DCListFind(head, 3));
DCListPrint(head);
DCListDestory(&head);
return 0;
}