typedef int LTDataType; //数据域的数据类型
typedef struct ListNode //双向链表结点
{
LTDataType data; //存储有效数据
struct ListNode* prev; //存储前趋结点
struct ListNode* next; //存储后继结点
}ListNode;
代码实现
// 创建返回链表的头结点.
ListNode* ListCreate()
{
ListNode* head = (ListNode*)malloc(sizeof(ListNode));
if (NULL == head)
{
perror("malloc");
exit(-1);
}
head->prev = head; //头结点的前趋指针指向自己
head->next = head; //头结点的后继指针指向自己
return head; //返回创建好的头结点
}
实现方法
代码实现
// 创建一个新结点
ListNode* BuySListNode(LTDataType x)
{
ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
if (NULL == newnode)
{
perror("malloc");
exit(-1);
}
newnode->data = x; //新结点数据域存储传来的数据
newnode->next = NULL; //新结点前趋指针暂时指向 NULL
newnode->prev = NULL; //新结点后继指针暂时指向 NULL
return newnode; //返回创建好的新结点
}
实现方法
先定义一个 cur 指针指向头结点的后继结点,删除链表时有两种情况。
代码实现
// 双向链表销毁
void ListDestory(ListNode* pHead)
{
assert(pHead);
ListNode* cur = pHead->next; //指向头结点的下一个结点
while (cur != pHead)
{
ListNode* next = cur->next; //存储当前结点的下一个结点的地址
free(cur); //释放当前结点
cur = next; //让 cur 指向 cur 的下一个结点
}
free(pHead); //不管链表开始是不是为空最后都会释放头结点
pHead = NULL;
}
实现方法
代码实现
// 双向链表打印
void ListPrint(ListNode* pHead)
{
assert(pHead); //传过来的不是个空指针
ListNode* cur = pHead->next; //指向头结点的下一个结点(首结点)
printf("头结点<->");
while (cur != pHead) //不指向头结点时说明链表中还有结点未遍历到
{
printf("%d<->", cur->data); //输出结点数据域的内容
cur = cur->next; //指向当前结点的下一个结点
}
printf("\n");
}
实现方法
代码实现
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x)
{
assert(pHead); //传过来的不是个空指针
ListNode* newnode = BuySListNode(x); //先创建要插入的新结点
ListNode* tail = pHead->prev; //找到双向链表的尾结点
tail->next = newnode; //尾结点的后继指针指向新结点
newnode->prev = tail; //新结点的前趋指针指向尾结点
newnode->next = pHead; //新结点的后继结点指向头结点
pHead->prev = newnode; //头结点的前趋指针指向新结点
}
实现方法
代码实现
// 双向链表尾删
void ListPopBack(ListNode* pHead)
{
assert(pHead);
assert(pHead->next != pHead->prev); //不是空链表
ListNode* tail = pHead->prev; //找到链表的尾结点
ListNode* tail_prev = tail->prev; //找到尾结点的前一个结点
pHead->prev = tail_prev; //让头结点的前趋指针指向尾结点的前一个结点
tail_prev->next = pHead; //让尾结点的前一个结点的后继指针指向头结点
free(tail); //删除尾结点
tail = NULL;
}
实现方法
代码实现
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* newnode = BuySListNode(x); //创建新结点
ListNode* first = pHead->next; //保存首结点地址
pHead->next = newnode; //头结点后继指向新结点
newnode->prev = pHead; //新结点前趋指向头结点
newnode->next = first; //新结点后继指向首结点
first->prev = newnode; //首结点前趋指向新结点
}
实现方法
代码实现
// 双向链表头删
void ListPopFront(ListNode* pHead)
{
assert(pHead);
assert(pHead->next != pHead->prev); //链表不为空
ListNode* first = pHead->next; //指向首结点
ListNode* second = first->next; //指向第二个结点
pHead->next = second; //头结点的后继指针指向第二个结点
second->prev = pHead; //第二个结点的前趋指针指向头结点
free(first); //释放首结点
first = NULL;
}
代码实现
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x)
{
assert(pHead);
ListNode* cur = pHead->next; //链表不为空时指向首结点,链表为空时最后直接返回 NULL
while (cur != pHead) //链表还没彻底遍历一遍时继续指向循环体内容
{
if (cur->data == x) //结点数据域等于要查找的数
{
return cur; //返回出现要查找的数据的结点地址
}
cur = cur->next;
}
return NULL;
}
获取 pos 位置
实现方法
代码实现
// 双向链表在 pos 的前面进行插入
void ListInsert(ListNode* pos, LTDataType x)
{
assert(pos); //传过来的不是空指针
ListNode* newnode = BuySListNode(x); //创建新结点
ListNode* posprev = pos->prev; //保存 pos 的前一个结点
posprev->next = newnode; //前一个结点的 next 域指向新结点
newnode->prev = posprev; //新结点的 prev 域指向前一个结点
newnode->next = pos; //新结点的 next 域指向 pos 结点
pos->prev = newnode; //pos 的 prev 域指向新结点
}
功能特点
获取 pos 位置
实现方法
代码实现
// 双向链表删除 pos 位置的节点
void ListErase(ListNode* pos)
{
assert(pos);
ListNode* posprev = pos->prev; //保存 pos 位置结点的前趋结点
ListNode* posnext = pos->next; //保存 pos 位置结点的后继结点
posprev->next = posnext; //pos 前一个结点的后继指向 pos 的后一个结点
posnext->prev = posprev; //pos 后一个结点的前趋指向 pos 的前一个结点
free(pos);
pos = NULL;
}
功能特点
// 双向链表在 pos 的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除 pos 位置的节点
void ListErase(ListNode* pos);
1. 指向头尾插功能
ListInsert(pHead->next, xxx); //首结点为 pos,执行的是头插
ListInsert(pHead, xxx); //头结点为 pos,执行的是尾插
2. 执行头尾删功能
ListErase(pHead->next) //首结点为 pos,执行的是头删
ListErase(pHead->prev) //尾结点为 pos,执行的是尾删