目录
一、介绍
双向链表虽然看起来结构复杂,但是实现非常简单,可用场景也很丰富。
二、代码实现
1.List.h
#include <stdio.h>
#include <assert.h>
typedef int LTDataType;
typedef struct ListNode {
struct ListNode* next;
struct ListNode* prev;
LTDataType val;
}LTNode;
LTNode* LTInit();
void LTPrint(LTNode* phead);
void LTPushBack(LTNode* phead, LTDataType x);
void LTPopBack(LTNode* phead);
void LTPushFront(LTNode* phead, LTDataType x);
void LTPopFront(LTNode* phead);
LTNode* LTFind(LTNode* phead, LTDataType x);
void LTInsert(LTNode* pos, LTDataType x);
void LTErase(LTNode* pos);
void LTDestroy(LTNode* phead);
2.List.c
(0)创建节点(CreateLTNode)
LTNode* CreateLTNode(LTDataType x) {
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL) {
perror("malloc fail");
exit(-1);
}
newnode->val = x;
newnode->next = NULL;
newnode->prev = NULL;
return newnode;
}
(1)链表初始化 (LTInit)
LTNode* LTInit() {
LTNode* phead = CreateLTNode(-1);
phead->next = phead;
phead->prev = phead;
return phead;
}
(2)链表打印 (LTPrint)
void LTPrint(LTNode* phead) {
assert(phead);
printf("哨兵位<=>");
LTNode* cur = phead->next;
while (cur != phead) {
printf("%d<=>", cur->val);
cur = cur->next;
}
printf("\n");
}
(3)尾插 (LTPushBack)
void LTPushBack(LTNode* phead, LTDataType x) {
assert(phead);
LTNode* tail = phead->prev;
LTNode* newnode = CreateLTNode(x);
tail->next = newnode;
newnode->next = phead;
phead->prev = newnode;
}
(4)尾删 (LTPopBack)
void LTPopBack(LTNode* phead) {
assert(phead);
assert(phead->next != phead);
LTNode* tail = phead->prev;
LTNode* tailPrev = tail->prev;
free(tail);
tailPrev->next = phead;
phead->prev = tailPrev;
}
(5)头插 (LTPushFront)
void LTPushFront(LTNode* phead, LTDataType x) {
//第一种写法
assert(phead);
LTNode* newnode = CreateLTNode(x);
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
}
也可以再创建一个结点指针,方便操作
void LTPushFront(LTNode* phead, LTDataType x) {
//第一种写法
//assert(phead);
//LTNode* newnode = CreateLTNode(x);
//newnode->next = phead->next;
//phead->next->prev = newnode;
//phead->next = newnode;
//newnode->prev = phead;
//第二种写法
assert(phead);
LTNode* newnode = CreateLTNode(x);
LTNode* first = phead->next;
newnode->next = first;
first->prev = newnode;
phead->next = newnode;
newnode->prev = phead;
}
(6)头删 (LTPopFront)
void LTPopFront(LTNode* phead) {
assert(phead);
assert(phead->next != phead);
LTNode* first = phead->next;
LTNode* second = first->next;
phead->next = second;
second->prev = phead;
free(first);
first = NULL;
}
(7)查找节点 (LTFind)
LTNode* LTFind(LTNode* phead, LTDataType x) {
assert(phead);
LTNode* cur = phead->next;
while (cur != phead) {
if (cur - .cal == x) {
return cur;
}
cur = cur->next;
}
return NULL;
}
(8)指定位置插入 (LTInsert)
void LTInsert(LTNode* pos, LTDataType x) {
assert(pos);
LTNode* posPrev = pos->prev;
LTNode* newnode = CreateLTNode(x);
posPrev->next = newnode;
newnode->next = pos;
newnode->prev = posPrev;
pos->prev = newnode;
}
(9)指定位置删除 (LTErase)
void LTErase(LTNode* pos) {
assert(pos);
LTNode* posNext = pos->next;
LTNode* posPrev = pos->prev;
posPrev->next = posNext;
posNext->prev = posPrev;
free(pos);
pos = NULL;
}
实现了指定位置的插入删除,头尾操作可以舍弃了。我们有哨兵位,很容易找到头尾。
(10)链表销毁 (LTDestroy)
void LTDestroy(LTNode* phead) {
assert(phead);
LTNode* cur = phead->next;
while (cur != phead) {
LTNode* next = cur->next;
free(cur);
cur = next;
}
free(phead);
}