C语言数据结构系列:双链表与循环链表篇
- C语言数据结构系列(三):双链表与循环链表
C语言数据结构系列(三):双链表与循环链表
🎯 本篇目标:掌握双链表和循环链表的概念与实现,理解它们相比单链表的优势!
一、前言
哈喽小伙伴们!👋
上一篇我们学习了单链表,它只能单向遍历,想要找前一个节点还得从头开始找,太不方便了!😫
今天我们来学习两个链表的"进化版":
- 双链表 :可以双向行走,前进后退都很方便!
- 循环链表 :首尾相连,形成一个闭环,适合约瑟夫等问题!
#mermaid-svg-NOuo30If5vRy1W8E{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NOuo30If5vRy1W8E .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NOuo30If5vRy1W8E .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NOuo30If5vRy1W8E .error-icon{fill:#552222;}#mermaid-svg-NOuo30If5vRy1W8E .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NOuo30If5vRy1W8E .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NOuo30If5vRy1W8E .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NOuo30If5vRy1W8E .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NOuo30If5vRy1W8E .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NOuo30If5vRy1W8E .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NOuo30If5vRy1W8E .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NOuo30If5vRy1W8E .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NOuo30If5vRy1W8E .marker.cross{stroke:#333333;}#mermaid-svg-NOuo30If5vRy1W8E svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NOuo30If5vRy1W8E p{margin:0;}#mermaid-svg-NOuo30If5vRy1W8E .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NOuo30If5vRy1W8E .cluster-label text{fill:#333;}#mermaid-svg-NOuo30If5vRy1W8E .cluster-label span{color:#333;}#mermaid-svg-NOuo30If5vRy1W8E .cluster-label span p{background-color:transparent;}#mermaid-svg-NOuo30If5vRy1W8E .label text,#mermaid-svg-NOuo30If5vRy1W8E span{fill:#333;color:#333;}#mermaid-svg-NOuo30If5vRy1W8E .node rect,#mermaid-svg-NOuo30If5vRy1W8E .node circle,#mermaid-svg-NOuo30If5vRy1W8E .node ellipse,#mermaid-svg-NOuo30If5vRy1W8E .node polygon,#mermaid-svg-NOuo30If5vRy1W8E .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NOuo30If5vRy1W8E .rough-node .label text,#mermaid-svg-NOuo30If5vRy1W8E .node .label text,#mermaid-svg-NOuo30If5vRy1W8E .image-shape .label,#mermaid-svg-NOuo30If5vRy1W8E .icon-shape .label{text-anchor:middle;}#mermaid-svg-NOuo30If5vRy1W8E .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NOuo30If5vRy1W8E .rough-node .label,#mermaid-svg-NOuo30If5vRy1W8E .node .label,#mermaid-svg-NOuo30If5vRy1W8E .image-shape .label,#mermaid-svg-NOuo30If5vRy1W8E .icon-shape .label{text-align:center;}#mermaid-svg-NOuo30If5vRy1W8E .node.clickable{cursor:pointer;}#mermaid-svg-NOuo30If5vRy1W8E .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NOuo30If5vRy1W8E .arrowheadPath{fill:#333333;}#mermaid-svg-NOuo30If5vRy1W8E .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NOuo30If5vRy1W8E .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NOuo30If5vRy1W8E .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NOuo30If5vRy1W8E .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NOuo30If5vRy1W8E .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NOuo30If5vRy1W8E .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NOuo30If5vRy1W8E .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NOuo30If5vRy1W8E .cluster text{fill:#333;}#mermaid-svg-NOuo30If5vRy1W8E .cluster span{color:#333;}#mermaid-svg-NOuo30If5vRy1W8E div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NOuo30If5vRy1W8E .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NOuo30If5vRy1W8E rect.text{fill:none;stroke-width:0;}#mermaid-svg-NOuo30If5vRy1W8E .icon-shape,#mermaid-svg-NOuo30If5vRy1W8E .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NOuo30If5vRy1W8E .icon-shape p,#mermaid-svg-NOuo30If5vRy1W8E .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NOuo30If5vRy1W8E .icon-shape .label rect,#mermaid-svg-NOuo30If5vRy1W8E .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NOuo30If5vRy1W8E .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NOuo30If5vRy1W8E .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NOuo30If5vRy1W8E :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 双链表
NULL
节点1
节点2
NULL
让我们开始今天的学习吧! 🚀
二、双链表
2.1 什么是双链表?
双链表(Doubly Linked List) 每个节点包含三个域:前驱指针、数据域、后继指针。
就像一列双向火车🚆:
- 每节车厢可以往前走,也可以往后走
- 每节车厢都知道自己的前一节和后一节是谁
2.2 节点结构
#mermaid-svg-ZeHQKmO5WH7a93UO{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZeHQKmO5WH7a93UO .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZeHQKmO5WH7a93UO .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZeHQKmO5WH7a93UO .error-icon{fill:#552222;}#mermaid-svg-ZeHQKmO5WH7a93UO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZeHQKmO5WH7a93UO .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZeHQKmO5WH7a93UO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZeHQKmO5WH7a93UO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZeHQKmO5WH7a93UO .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZeHQKmO5WH7a93UO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZeHQKmO5WH7a93UO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZeHQKmO5WH7a93UO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZeHQKmO5WH7a93UO .marker.cross{stroke:#333333;}#mermaid-svg-ZeHQKmO5WH7a93UO svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZeHQKmO5WH7a93UO p{margin:0;}#mermaid-svg-ZeHQKmO5WH7a93UO .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZeHQKmO5WH7a93UO .cluster-label text{fill:#333;}#mermaid-svg-ZeHQKmO5WH7a93UO .cluster-label span{color:#333;}#mermaid-svg-ZeHQKmO5WH7a93UO .cluster-label span p{background-color:transparent;}#mermaid-svg-ZeHQKmO5WH7a93UO .label text,#mermaid-svg-ZeHQKmO5WH7a93UO span{fill:#333;color:#333;}#mermaid-svg-ZeHQKmO5WH7a93UO .node rect,#mermaid-svg-ZeHQKmO5WH7a93UO .node circle,#mermaid-svg-ZeHQKmO5WH7a93UO .node ellipse,#mermaid-svg-ZeHQKmO5WH7a93UO .node polygon,#mermaid-svg-ZeHQKmO5WH7a93UO .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZeHQKmO5WH7a93UO .rough-node .label text,#mermaid-svg-ZeHQKmO5WH7a93UO .node .label text,#mermaid-svg-ZeHQKmO5WH7a93UO .image-shape .label,#mermaid-svg-ZeHQKmO5WH7a93UO .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZeHQKmO5WH7a93UO .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZeHQKmO5WH7a93UO .rough-node .label,#mermaid-svg-ZeHQKmO5WH7a93UO .node .label,#mermaid-svg-ZeHQKmO5WH7a93UO .image-shape .label,#mermaid-svg-ZeHQKmO5WH7a93UO .icon-shape .label{text-align:center;}#mermaid-svg-ZeHQKmO5WH7a93UO .node.clickable{cursor:pointer;}#mermaid-svg-ZeHQKmO5WH7a93UO .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZeHQKmO5WH7a93UO .arrowheadPath{fill:#333333;}#mermaid-svg-ZeHQKmO5WH7a93UO .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZeHQKmO5WH7a93UO .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZeHQKmO5WH7a93UO .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZeHQKmO5WH7a93UO .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZeHQKmO5WH7a93UO .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZeHQKmO5WH7a93UO .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZeHQKmO5WH7a93UO .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZeHQKmO5WH7a93UO .cluster text{fill:#333;}#mermaid-svg-ZeHQKmO5WH7a93UO .cluster span{color:#333;}#mermaid-svg-ZeHQKmO5WH7a93UO div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZeHQKmO5WH7a93UO .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZeHQKmO5WH7a93UO rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZeHQKmO5WH7a93UO .icon-shape,#mermaid-svg-ZeHQKmO5WH7a93UO .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZeHQKmO5WH7a93UO .icon-shape p,#mermaid-svg-ZeHQKmO5WH7a93UO .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZeHQKmO5WH7a93UO .icon-shape .label rect,#mermaid-svg-ZeHQKmO5WH7a93UO .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZeHQKmO5WH7a93UO .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZeHQKmO5WH7a93UO .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZeHQKmO5WH7a93UO :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 双链表节点
prev
前驱指针
data
数据域
next
后继指针
C语言结构体定义:
c
// 双链表节点结构体
typedef struct DNode {
int data; // 数据域
struct DNode *prev; // 前驱指针
struct DNode *next; // 后继指针
} DNode;
2.3 双链表 vs 单链表
| 特性 | 单链表 | 双链表 |
|---|---|---|
| 指针数 | 1个(next) | 2个(prev, next) |
| 遍历方向 | 单向 | 双向 |
| 查找前驱 | O(n) | O(1) |
| 空间开销 | 较小 | 较大 |
| 插入删除 | 需知道前驱 | 直接操作 |
2.4 双链表的基本操作
创建节点
c
DNode* createDNode(int value) {
DNode *newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = value;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
头插法
#mermaid-svg-uAqDANVebp3IbRGe{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uAqDANVebp3IbRGe .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uAqDANVebp3IbRGe .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uAqDANVebp3IbRGe .error-icon{fill:#552222;}#mermaid-svg-uAqDANVebp3IbRGe .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uAqDANVebp3IbRGe .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uAqDANVebp3IbRGe .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uAqDANVebp3IbRGe .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uAqDANVebp3IbRGe .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uAqDANVebp3IbRGe .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uAqDANVebp3IbRGe .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uAqDANVebp3IbRGe .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uAqDANVebp3IbRGe .marker.cross{stroke:#333333;}#mermaid-svg-uAqDANVebp3IbRGe svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uAqDANVebp3IbRGe p{margin:0;}#mermaid-svg-uAqDANVebp3IbRGe .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-uAqDANVebp3IbRGe .cluster-label text{fill:#333;}#mermaid-svg-uAqDANVebp3IbRGe .cluster-label span{color:#333;}#mermaid-svg-uAqDANVebp3IbRGe .cluster-label span p{background-color:transparent;}#mermaid-svg-uAqDANVebp3IbRGe .label text,#mermaid-svg-uAqDANVebp3IbRGe span{fill:#333;color:#333;}#mermaid-svg-uAqDANVebp3IbRGe .node rect,#mermaid-svg-uAqDANVebp3IbRGe .node circle,#mermaid-svg-uAqDANVebp3IbRGe .node ellipse,#mermaid-svg-uAqDANVebp3IbRGe .node polygon,#mermaid-svg-uAqDANVebp3IbRGe .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uAqDANVebp3IbRGe .rough-node .label text,#mermaid-svg-uAqDANVebp3IbRGe .node .label text,#mermaid-svg-uAqDANVebp3IbRGe .image-shape .label,#mermaid-svg-uAqDANVebp3IbRGe .icon-shape .label{text-anchor:middle;}#mermaid-svg-uAqDANVebp3IbRGe .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uAqDANVebp3IbRGe .rough-node .label,#mermaid-svg-uAqDANVebp3IbRGe .node .label,#mermaid-svg-uAqDANVebp3IbRGe .image-shape .label,#mermaid-svg-uAqDANVebp3IbRGe .icon-shape .label{text-align:center;}#mermaid-svg-uAqDANVebp3IbRGe .node.clickable{cursor:pointer;}#mermaid-svg-uAqDANVebp3IbRGe .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uAqDANVebp3IbRGe .arrowheadPath{fill:#333333;}#mermaid-svg-uAqDANVebp3IbRGe .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uAqDANVebp3IbRGe .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uAqDANVebp3IbRGe .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uAqDANVebp3IbRGe .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uAqDANVebp3IbRGe .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uAqDANVebp3IbRGe .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uAqDANVebp3IbRGe .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uAqDANVebp3IbRGe .cluster text{fill:#333;}#mermaid-svg-uAqDANVebp3IbRGe .cluster span{color:#333;}#mermaid-svg-uAqDANVebp3IbRGe div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-uAqDANVebp3IbRGe .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uAqDANVebp3IbRGe rect.text{fill:none;stroke-width:0;}#mermaid-svg-uAqDANVebp3IbRGe .icon-shape,#mermaid-svg-uAqDANVebp3IbRGe .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uAqDANVebp3IbRGe .icon-shape p,#mermaid-svg-uAqDANVebp3IbRGe .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uAqDANVebp3IbRGe .icon-shape .label rect,#mermaid-svg-uAqDANVebp3IbRGe .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uAqDANVebp3IbRGe .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uAqDANVebp3IbRGe .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uAqDANVebp3IbRGe :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} next
prev
双向连接
新节点
原头节点
c
void insertAtHead(DNode **head, int value) {
DNode *newNode = createDNode(value);
if (*head != NULL) {
newNode->next = *head;
(*head)->prev = newNode;
}
*head = newNode;
}
尾插法
c
void insertAtTail(DNode **head, int value) {
DNode *newNode = createDNode(value);
if (*head == NULL) {
*head = newNode;
return;
}
DNode *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
newNode->prev = current;
}
指定位置插入
c
void insertAtPos(DNode **head, int pos, int value) {
if (pos == 0) {
insertAtHead(head, value);
return;
}
DNode *current = *head;
for (int i = 0; i < pos && current != NULL; i++) {
current = current->next;
}
if (current == NULL) {
printf("位置无效!\n");
return;
}
DNode *newNode = createDNode(value);
newNode->prev = current->prev;
newNode->next = current;
current->prev->next = newNode;
current->prev = newNode;
}
删除节点
c
void deleteNode(DNode **head, int value) {
if (*head == NULL) return;
DNode *current = *head;
// 找到要删除的节点
while (current != NULL && current->data != value) {
current = current->next;
}
if (current == NULL) {
printf("未找到值为%d的节点!\n", value);
return;
}
// 如果是头节点
if (current->prev == NULL) {
*head = current->next;
if (*head != NULL)
(*head)->prev = NULL;
} else {
current->prev->next = current->next;
if (current->next != NULL)
current->next->prev = current->prev;
}
free(current);
}
反向打印
双链表的独特优势------可以从后往前打印!
c
void printReverse(DNode *head) {
if (head == NULL) return;
// 先走到最后
DNode *current = head;
while (current->next != NULL) {
current = current->next;
}
// 从后往前打印
while (current != NULL) {
printf("%d", current->data);
if (current->prev) printf(" <- ");
current = current->prev;
}
printf("\n");
}
2.5 完整示例
c
#include <stdio.h>
#include <stdlib.h>
typedef struct DNode {
int data;
struct DNode *prev;
struct DNode *next;
} DNode;
DNode* createDNode(int value) {
DNode *newNode = (DNode*)malloc(sizeof(DNode));
newNode->data = value;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
void insertAtHead(DNode **head, int value) {
DNode *newNode = createDNode(value);
if (*head != NULL) {
newNode->next = *head;
(*head)->prev = newNode;
}
*head = newNode;
}
void insertAtTail(DNode **head, int value) {
DNode *newNode = createDNode(value);
if (*head == NULL) {
*head = newNode;
return;
}
DNode *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
newNode->prev = current;
}
void deleteNode(DNode **head, int value) {
if (*head == NULL) return;
DNode *current = *head;
while (current != NULL && current->data != value) {
current = current->next;
}
if (current == NULL) return;
if (current->prev == NULL) {
*head = current->next;
if (*head) (*head)->prev = NULL;
} else {
current->prev->next = current->next;
if (current->next) current->next->prev = current->prev;
}
free(current);
}
void printList(DNode *head) {
DNode *current = head;
while (current != NULL) {
printf("%d", current->data);
if (current->next) printf(" <-> ");
current = current->next;
}
printf("\n");
}
void printReverse(DNode *head) {
if (head == NULL) return;
DNode *current = head;
while (current->next != NULL) current = current->next;
while (current != NULL) {
printf("%d", current->data);
if (current->prev) printf(" <-> ");
current = current->prev;
}
printf("\n");
}
void freeList(DNode **head) {
DNode *current = *head;
while (current != NULL) {
DNode *temp = current;
current = current->next;
free(temp);
}
*head = NULL;
}
int main() {
DNode *head = NULL;
printf("===== 双链表演示 =====\n\n");
insertAtTail(&head, 10);
insertAtTail(&head, 20);
insertAtTail(&head, 30);
insertAtHead(&head, 5);
printf("正向打印: ");
printList(head);
printf("反向打印: ");
printReverse(head);
printf("\n删除元素20后:\n");
deleteNode(&head, 20);
printf("正向打印: ");
printList(head);
freeList(&head);
return 0;
}
运行结果:
===== 双链表演示 =====
正向打印: 5 <-> 10 <-> 20 <-> 30
反向打印: 30 <-> 20 <-> 10 <-> 5
删除元素20后:
正向打印: 5 <-> 10 <-> 30
三、循环链表
3.1 什么是循环链表?
循环链表(Circular Linked List) 是一种首尾相接的链表,最后一个节点的next指向第一个节点,形成一个闭环!
就像一个旋转木马🎠:
- 没有起点也没有终点
- 可以一直循环下去
- 适合处理约瑟夫问题、循环队列等
#mermaid-svg-7YVUCNWW8YuQZN5p{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-7YVUCNWW8YuQZN5p .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-7YVUCNWW8YuQZN5p .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-7YVUCNWW8YuQZN5p .error-icon{fill:#552222;}#mermaid-svg-7YVUCNWW8YuQZN5p .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-7YVUCNWW8YuQZN5p .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-7YVUCNWW8YuQZN5p .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-7YVUCNWW8YuQZN5p .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-7YVUCNWW8YuQZN5p .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-7YVUCNWW8YuQZN5p .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-7YVUCNWW8YuQZN5p .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-7YVUCNWW8YuQZN5p .marker{fill:#333333;stroke:#333333;}#mermaid-svg-7YVUCNWW8YuQZN5p .marker.cross{stroke:#333333;}#mermaid-svg-7YVUCNWW8YuQZN5p svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-7YVUCNWW8YuQZN5p p{margin:0;}#mermaid-svg-7YVUCNWW8YuQZN5p .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-7YVUCNWW8YuQZN5p .cluster-label text{fill:#333;}#mermaid-svg-7YVUCNWW8YuQZN5p .cluster-label span{color:#333;}#mermaid-svg-7YVUCNWW8YuQZN5p .cluster-label span p{background-color:transparent;}#mermaid-svg-7YVUCNWW8YuQZN5p .label text,#mermaid-svg-7YVUCNWW8YuQZN5p span{fill:#333;color:#333;}#mermaid-svg-7YVUCNWW8YuQZN5p .node rect,#mermaid-svg-7YVUCNWW8YuQZN5p .node circle,#mermaid-svg-7YVUCNWW8YuQZN5p .node ellipse,#mermaid-svg-7YVUCNWW8YuQZN5p .node polygon,#mermaid-svg-7YVUCNWW8YuQZN5p .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-7YVUCNWW8YuQZN5p .rough-node .label text,#mermaid-svg-7YVUCNWW8YuQZN5p .node .label text,#mermaid-svg-7YVUCNWW8YuQZN5p .image-shape .label,#mermaid-svg-7YVUCNWW8YuQZN5p .icon-shape .label{text-anchor:middle;}#mermaid-svg-7YVUCNWW8YuQZN5p .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-7YVUCNWW8YuQZN5p .rough-node .label,#mermaid-svg-7YVUCNWW8YuQZN5p .node .label,#mermaid-svg-7YVUCNWW8YuQZN5p .image-shape .label,#mermaid-svg-7YVUCNWW8YuQZN5p .icon-shape .label{text-align:center;}#mermaid-svg-7YVUCNWW8YuQZN5p .node.clickable{cursor:pointer;}#mermaid-svg-7YVUCNWW8YuQZN5p .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-7YVUCNWW8YuQZN5p .arrowheadPath{fill:#333333;}#mermaid-svg-7YVUCNWW8YuQZN5p .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-7YVUCNWW8YuQZN5p .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-7YVUCNWW8YuQZN5p .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7YVUCNWW8YuQZN5p .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-7YVUCNWW8YuQZN5p .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7YVUCNWW8YuQZN5p .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-7YVUCNWW8YuQZN5p .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-7YVUCNWW8YuQZN5p .cluster text{fill:#333;}#mermaid-svg-7YVUCNWW8YuQZN5p .cluster span{color:#333;}#mermaid-svg-7YVUCNWW8YuQZN5p div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-7YVUCNWW8YuQZN5p .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-7YVUCNWW8YuQZN5p rect.text{fill:none;stroke-width:0;}#mermaid-svg-7YVUCNWW8YuQZN5p .icon-shape,#mermaid-svg-7YVUCNWW8YuQZN5p .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-7YVUCNWW8YuQZN5p .icon-shape p,#mermaid-svg-7YVUCNWW8YuQZN5p .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-7YVUCNWW8YuQZN5p .icon-shape .label rect,#mermaid-svg-7YVUCNWW8YuQZN5p .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-7YVUCNWW8YuQZN5p .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-7YVUCNWW8YuQZN5p .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-7YVUCNWW8YuQZN5p :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 回到起点
节点1
节点2
节点3
节点4
3.2 循环链表 vs 普通链表
| 特性 | 普通链表 | 循环链表 |
|---|---|---|
| 尾节点next | NULL | 指向头节点 |
| 遍历结束条件 | current == NULL | current->next == head |
| 形成结构 | 线性 | 环形 |
3.3 循环链表的基本操作
创建节点
c
CLNode* createCLNode(int value) {
CLNode *newNode = (CLNode*)malloc(sizeof(CLNode));
newNode->data = value;
newNode->next = NULL;
return newNode;
}
尾插法
#mermaid-svg-HEb72lpz36VfYbqX{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HEb72lpz36VfYbqX .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HEb72lpz36VfYbqX .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HEb72lpz36VfYbqX .error-icon{fill:#552222;}#mermaid-svg-HEb72lpz36VfYbqX .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HEb72lpz36VfYbqX .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HEb72lpz36VfYbqX .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HEb72lpz36VfYbqX .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HEb72lpz36VfYbqX .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HEb72lpz36VfYbqX .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HEb72lpz36VfYbqX .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HEb72lpz36VfYbqX .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HEb72lpz36VfYbqX .marker.cross{stroke:#333333;}#mermaid-svg-HEb72lpz36VfYbqX svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HEb72lpz36VfYbqX p{margin:0;}#mermaid-svg-HEb72lpz36VfYbqX .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HEb72lpz36VfYbqX .cluster-label text{fill:#333;}#mermaid-svg-HEb72lpz36VfYbqX .cluster-label span{color:#333;}#mermaid-svg-HEb72lpz36VfYbqX .cluster-label span p{background-color:transparent;}#mermaid-svg-HEb72lpz36VfYbqX .label text,#mermaid-svg-HEb72lpz36VfYbqX span{fill:#333;color:#333;}#mermaid-svg-HEb72lpz36VfYbqX .node rect,#mermaid-svg-HEb72lpz36VfYbqX .node circle,#mermaid-svg-HEb72lpz36VfYbqX .node ellipse,#mermaid-svg-HEb72lpz36VfYbqX .node polygon,#mermaid-svg-HEb72lpz36VfYbqX .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HEb72lpz36VfYbqX .rough-node .label text,#mermaid-svg-HEb72lpz36VfYbqX .node .label text,#mermaid-svg-HEb72lpz36VfYbqX .image-shape .label,#mermaid-svg-HEb72lpz36VfYbqX .icon-shape .label{text-anchor:middle;}#mermaid-svg-HEb72lpz36VfYbqX .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HEb72lpz36VfYbqX .rough-node .label,#mermaid-svg-HEb72lpz36VfYbqX .node .label,#mermaid-svg-HEb72lpz36VfYbqX .image-shape .label,#mermaid-svg-HEb72lpz36VfYbqX .icon-shape .label{text-align:center;}#mermaid-svg-HEb72lpz36VfYbqX .node.clickable{cursor:pointer;}#mermaid-svg-HEb72lpz36VfYbqX .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HEb72lpz36VfYbqX .arrowheadPath{fill:#333333;}#mermaid-svg-HEb72lpz36VfYbqX .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HEb72lpz36VfYbqX .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HEb72lpz36VfYbqX .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HEb72lpz36VfYbqX .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HEb72lpz36VfYbqX .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HEb72lpz36VfYbqX .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HEb72lpz36VfYbqX .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HEb72lpz36VfYbqX .cluster text{fill:#333;}#mermaid-svg-HEb72lpz36VfYbqX .cluster span{color:#333;}#mermaid-svg-HEb72lpz36VfYbqX div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HEb72lpz36VfYbqX .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HEb72lpz36VfYbqX rect.text{fill:none;stroke-width:0;}#mermaid-svg-HEb72lpz36VfYbqX .icon-shape,#mermaid-svg-HEb72lpz36VfYbqX .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HEb72lpz36VfYbqX .icon-shape p,#mermaid-svg-HEb72lpz36VfYbqX .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HEb72lpz36VfYbqX .icon-shape .label rect,#mermaid-svg-HEb72lpz36VfYbqX .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HEb72lpz36VfYbqX .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HEb72lpz36VfYbqX .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HEb72lpz36VfYbqX :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 插入
回到起点
节点1
节点2
节点3
新节点
c
void insertAtTail(CLNode **head, int value) {
CLNode *newNode = createCLNode(value);
if (*head == NULL) {
*head = newNode;
newNode->next = *head; // 指向自己
return;
}
CLNode *current = *head;
while (current->next != *head) {
current = current->next;
}
current->next = newNode;
newNode->next = *head; // 新节点指向头节点
}
打印循环链表
c
void printList(CLNode *head) {
if (head == NULL) return;
CLNode *current = head;
do {
printf("%d", current->data);
if (current->next != head) printf(" -> ");
current = current->next;
} while (current != head);
printf(" (回到%d)\n", head->data);
}
删除节点
c
void deleteNode(CLNode **head, int value) {
if (*head == NULL) return;
CLNode *current = *head;
CLNode *prev = NULL;
// 找到要删除的节点
do {
if (current->data == value) break;
prev = current;
current = current->next;
} while (current != *head);
// 没找到
if (current->data != value) {
printf("未找到值为%d的节点!\n", value);
return;
}
// 只有一个节点
if (current->next == current) {
*head = NULL;
} else {
if (current == *head) {
*head = current->next;
}
prev->next = current->next;
}
free(current);
}
3.4 约瑟夫问题(经典应用)
💡 问题描述:n个人围成一圈,从第一个人开始报数,报到m的人出圈,求出圈顺序。
#mermaid-svg-VhhVG8QIE3gEEytp{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-VhhVG8QIE3gEEytp .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-VhhVG8QIE3gEEytp .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-VhhVG8QIE3gEEytp .error-icon{fill:#552222;}#mermaid-svg-VhhVG8QIE3gEEytp .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-VhhVG8QIE3gEEytp .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-VhhVG8QIE3gEEytp .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-VhhVG8QIE3gEEytp .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-VhhVG8QIE3gEEytp .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-VhhVG8QIE3gEEytp .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-VhhVG8QIE3gEEytp .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-VhhVG8QIE3gEEytp .marker{fill:#333333;stroke:#333333;}#mermaid-svg-VhhVG8QIE3gEEytp .marker.cross{stroke:#333333;}#mermaid-svg-VhhVG8QIE3gEEytp svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-VhhVG8QIE3gEEytp p{margin:0;}#mermaid-svg-VhhVG8QIE3gEEytp .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-VhhVG8QIE3gEEytp .cluster-label text{fill:#333;}#mermaid-svg-VhhVG8QIE3gEEytp .cluster-label span{color:#333;}#mermaid-svg-VhhVG8QIE3gEEytp .cluster-label span p{background-color:transparent;}#mermaid-svg-VhhVG8QIE3gEEytp .label text,#mermaid-svg-VhhVG8QIE3gEEytp span{fill:#333;color:#333;}#mermaid-svg-VhhVG8QIE3gEEytp .node rect,#mermaid-svg-VhhVG8QIE3gEEytp .node circle,#mermaid-svg-VhhVG8QIE3gEEytp .node ellipse,#mermaid-svg-VhhVG8QIE3gEEytp .node polygon,#mermaid-svg-VhhVG8QIE3gEEytp .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-VhhVG8QIE3gEEytp .rough-node .label text,#mermaid-svg-VhhVG8QIE3gEEytp .node .label text,#mermaid-svg-VhhVG8QIE3gEEytp .image-shape .label,#mermaid-svg-VhhVG8QIE3gEEytp .icon-shape .label{text-anchor:middle;}#mermaid-svg-VhhVG8QIE3gEEytp .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-VhhVG8QIE3gEEytp .rough-node .label,#mermaid-svg-VhhVG8QIE3gEEytp .node .label,#mermaid-svg-VhhVG8QIE3gEEytp .image-shape .label,#mermaid-svg-VhhVG8QIE3gEEytp .icon-shape .label{text-align:center;}#mermaid-svg-VhhVG8QIE3gEEytp .node.clickable{cursor:pointer;}#mermaid-svg-VhhVG8QIE3gEEytp .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-VhhVG8QIE3gEEytp .arrowheadPath{fill:#333333;}#mermaid-svg-VhhVG8QIE3gEEytp .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-VhhVG8QIE3gEEytp .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-VhhVG8QIE3gEEytp .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VhhVG8QIE3gEEytp .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-VhhVG8QIE3gEEytp .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VhhVG8QIE3gEEytp .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-VhhVG8QIE3gEEytp .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-VhhVG8QIE3gEEytp .cluster text{fill:#333;}#mermaid-svg-VhhVG8QIE3gEEytp .cluster span{color:#333;}#mermaid-svg-VhhVG8QIE3gEEytp div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-VhhVG8QIE3gEEytp .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-VhhVG8QIE3gEEytp rect.text{fill:none;stroke-width:0;}#mermaid-svg-VhhVG8QIE3gEEytp .icon-shape,#mermaid-svg-VhhVG8QIE3gEEytp .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-VhhVG8QIE3gEEytp .icon-shape p,#mermaid-svg-VhhVG8QIE3gEEytp .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-VhhVG8QIE3gEEytp .icon-shape .label rect,#mermaid-svg-VhhVG8QIE3gEEytp .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-VhhVG8QIE3gEEytp .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-VhhVG8QIE3gEEytp .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-VhhVG8QIE3gEEytp :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 1
2
3
4
5
代码实现:
c
void josephus(int n, int m) {
// 创建循环链表
CLNode *head = NULL;
for (int i = n; i >= 1; i--) {
insertAtTail(&head, i);
}
printf("出圈顺序: ");
// 从第一个人开始,报数m-1次后删除
CLNode *current = head;
CLNode *prev = NULL;
while (current->next != current) {
// 报数m-1次
for (int i = 1; i < m; i++) {
prev = current;
current = current->next;
}
printf("%d ", current->data);
// 删除当前节点
prev->next = current->next;
free(current);
current = prev->next;
}
printf("%d\n", current->data); // 最后一个
free(current);
}
测试:
c
int main() {
printf("===== 约瑟夫问题 =====\n");
printf("n=5, m=3\n");
josephus(5, 3);
return 0;
}
运行结果:
===== 约瑟夫问题 =====
n=5, m=3
出圈顺序: 3 1 5 2 4
四、双向循环链表
💡 双向循环链表:结合双链表和循环链表的优点,既可以双向遍历,又可以循环!
4.1 节点结构
c
typedef struct DCNode {
int data;
struct DCNode *prev;
struct DCNode *next;
} DCNode;
4.2 创建和插入
c
DCNode* createDCNode(int value) {
DCNode *newNode = (DCNode*)malloc(sizeof(DCNode));
newNode->data = value;
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
void insertAtTail(DCNode **head, int value) {
DCNode *newNode = createDCNode(value);
if (*head == NULL) {
*head = newNode;
newNode->prev = newNode;
newNode->next = newNode;
return;
}
DCNode *tail = (*head)->prev;
tail->next = newNode;
newNode->prev = tail;
newNode->next = *head;
(*head)->prev = newNode;
}
4.3 打印
c
void printList(DCNode *head) {
if (head == NULL) return;
DCNode *current = head;
do {
printf("%d", current->data);
if (current->next != head) printf(" <-> ");
current = current->next;
} while (current != head);
printf("\n");
}
五、复杂度对比
| 操作 | 单链表 | 双链表 | 循环链表 |
|---|---|---|---|
| 头插法 | O(1) | O(1) | O(1) |
| 尾插法 | O(n) | O(n) | O(1)* |
| 删除已知节点 | O(n) | O(1) | O(n) |
| 查找前驱 | O(n) | O(1) | O(n) |
| 向前遍历 | ❌ | ✅ | ✅ |
*已知尾指针的情况下
六、应用场景
双链表的应用
-
浏览器的前进/后退 🔙
- 每个页面是一个节点,prev指向前一页,next指向后一页
-
音乐播放器 🎵
- 上一首/下一首功能
-
LRU缓存 💾
- 最近最少使用算法
循环链表的应用
-
约瑟夫问题 👥
- 多人围成一圈报数
-
轮询调度 ⏰
- 操作系统的时间片轮转
-
循环队列 🔄
- 打印任务队列
-
音乐播放循环 🔁
- 单曲循环、列表循环
七、练习题 🎯
🏠 基础题
题目1:合并两个有序双链表
将两个有序双链表合并为一个新的有序双链表。
题目2:判断回文链表
判断一个链表是否是回文链表(正读反读都一样)。
c
// 示例
1 -> 2 -> 2 -> 1 // 是回文
1 -> 2 -> 3 -> 4 // 不是回文
提示:可以使用快慢指针找到中间,然后反转后半部分比较。
💪 进阶题
题目3:LRU缓存实现
使用双向链表实现一个LRU缓存。
题目4:约瑟夫变体
n个人围成一圈,每个人有不同的权重,权重大的可以跳过多次。
八、总结
今天我们学习了两种链表的变体:
✅ 双链表:
- 每个节点有prev和next两个指针
- 可以双向遍历
- 删除已知节点O(1)
- 空间开销稍大
✅ 循环链表:
- 尾节点指向头节点,形成闭环
- 适合处理循环问题
- 约瑟夫问题的经典解法
✅ 双向循环链表:
- 结合两者优点
- Linux内核链表就是这种结构
选择建议:
- 需要双向遍历 → 双链表
- 需要循环操作 → 循环链表
- 需要两者兼备 → 双向循环链表
九、下篇预告
下一篇我们将学习 栈(Stack)------后进先出的数据结构!
#mermaid-svg-LyhqlaLdf5VNLWr9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-LyhqlaLdf5VNLWr9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-LyhqlaLdf5VNLWr9 .error-icon{fill:#552222;}#mermaid-svg-LyhqlaLdf5VNLWr9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-LyhqlaLdf5VNLWr9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-LyhqlaLdf5VNLWr9 .marker.cross{stroke:#333333;}#mermaid-svg-LyhqlaLdf5VNLWr9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-LyhqlaLdf5VNLWr9 p{margin:0;}#mermaid-svg-LyhqlaLdf5VNLWr9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-LyhqlaLdf5VNLWr9 .cluster-label text{fill:#333;}#mermaid-svg-LyhqlaLdf5VNLWr9 .cluster-label span{color:#333;}#mermaid-svg-LyhqlaLdf5VNLWr9 .cluster-label span p{background-color:transparent;}#mermaid-svg-LyhqlaLdf5VNLWr9 .label text,#mermaid-svg-LyhqlaLdf5VNLWr9 span{fill:#333;color:#333;}#mermaid-svg-LyhqlaLdf5VNLWr9 .node rect,#mermaid-svg-LyhqlaLdf5VNLWr9 .node circle,#mermaid-svg-LyhqlaLdf5VNLWr9 .node ellipse,#mermaid-svg-LyhqlaLdf5VNLWr9 .node polygon,#mermaid-svg-LyhqlaLdf5VNLWr9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-LyhqlaLdf5VNLWr9 .rough-node .label text,#mermaid-svg-LyhqlaLdf5VNLWr9 .node .label text,#mermaid-svg-LyhqlaLdf5VNLWr9 .image-shape .label,#mermaid-svg-LyhqlaLdf5VNLWr9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-LyhqlaLdf5VNLWr9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-LyhqlaLdf5VNLWr9 .rough-node .label,#mermaid-svg-LyhqlaLdf5VNLWr9 .node .label,#mermaid-svg-LyhqlaLdf5VNLWr9 .image-shape .label,#mermaid-svg-LyhqlaLdf5VNLWr9 .icon-shape .label{text-align:center;}#mermaid-svg-LyhqlaLdf5VNLWr9 .node.clickable{cursor:pointer;}#mermaid-svg-LyhqlaLdf5VNLWr9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-LyhqlaLdf5VNLWr9 .arrowheadPath{fill:#333333;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-LyhqlaLdf5VNLWr9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LyhqlaLdf5VNLWr9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-LyhqlaLdf5VNLWr9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LyhqlaLdf5VNLWr9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-LyhqlaLdf5VNLWr9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-LyhqlaLdf5VNLWr9 .cluster text{fill:#333;}#mermaid-svg-LyhqlaLdf5VNLWr9 .cluster span{color:#333;}#mermaid-svg-LyhqlaLdf5VNLWr9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-LyhqlaLdf5VNLWr9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-LyhqlaLdf5VNLWr9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-LyhqlaLdf5VNLWr9 .icon-shape,#mermaid-svg-LyhqlaLdf5VNLWr9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-LyhqlaLdf5VNLWr9 .icon-shape p,#mermaid-svg-LyhqlaLdf5VNLWr9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-LyhqlaLdf5VNLWr9 .icon-shape .label rect,#mermaid-svg-LyhqlaLdf5VNLWr9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-LyhqlaLdf5VNLWr9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-LyhqlaLdf5VNLWr9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-LyhqlaLdf5VNLWr9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 入栈 push
栈顶
出栈 pop
栈可以用数组或链表实现,让我们拭目以待! 🚀
💡 学习建议:双链表操作时要特别注意指针的指向,建议画图理解!
觉得有帮助就点赞+收藏+关注吧! 👍
有问题欢迎在评论区留言~ 💬