目录
1、单向链表基础:创建节点、头插法新增节点、遍历打印全部数据
[6、数组栈、链表栈两种方式实现:push 入栈、pop 出栈](#6、数组栈、链表栈两种方式实现:push 入栈、pop 出栈)
1、单向链表基础:创建节点、头插法新增节点、遍历打印全部数据
cpp
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
// 链表结点定义
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 初始化链表,带头结点
bool InitList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode));
if (L == NULL)
return false;
L->next = NULL;
return true;
}
// 头插法:在链表头部插入元素(头结点之后)
bool HeadInsert(LinkList &L, ElemType val)
{
// 新建结点s
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s == NULL)
return false;
s->data = val;// 新结点数据赋值
//新节点指向前一个节点的next,即下一个节点的data段,然后前一个节点的next再指向新节点的data段
s->next = L->next; // 新结点先接住后面第一个数据结点
L->next = s; // 头结点指向新结点
return true;
}
// 遍历打印所有有效结点
void PrintList(LinkList L)
{
LNode *p = L->next; // p跳过头结点,指向第一个数据节点
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
LinkList L;
InitList(L);
HeadInsert(L, 10);
HeadInsert(L, 20);
HeadInsert(L, 30);
printf("链表内容:");
PrintList(L);
// 输出:30 20 10
return 0;
}
2、链表尾插法,输入数字持续追加到链表末尾
cpp
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
// 链表结点定义
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 初始化链表,带头结点
bool InitList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode));
if (L == NULL)
return false;
L->next = NULL;
return true;
}
// 尾插法:在链表尾部插入元素(头结点之后)
bool TailInsert(LinkList &L, ElemType val)
{
// 新建结点s
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s == NULL)
return false;
s->data = val; // 新结点数据赋值
s->next = NULL; // 尾节点后面没有元素,置空
// 遍历找到链表最后一个节点
LNode *p = L; // p指向头结点,跳过头结点,指向第一个数据节点
while (p->next != NULL) // 遍历找到链表最后一个节点
{
p = p->next;
}
p->next = s; // 尾部节点指向新节点
return true;
}
// 遍历打印所有有效结点
void PrintList(LinkList L)
{
LNode *p = L->next; // p跳过头结点,指向第一个数据节点
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
LinkList L;
InitList(L);
TailInsert(L, 10);
TailInsert(L, 20);
TailInsert(L, 30);
printf("链表内容:");
PrintList(L);
// 输出:10 20 30
return 0;
}
3、根据值删除链表中指定节点
cpp
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 初始化链表,带头结点
bool InitList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;
return L != NULL;
}
// 尾插法
bool TailInsert(LinkList &L, ElemType val)
{
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = val;
s->next = NULL;
LNode *p = L;
while (p->next != NULL)
p = p->next;
p->next = s;
return true;
}
// 根据值删除第一个匹配节点
bool DeleteByValue(LinkList &L, ElemType val)
{
LNode *p = L, *del;
// p = L:p从头结点开始遍历(保存【前驱节点】)
// del:临时指针,用来存放要被删除的节点
// 条件1:p->next != NULL 后面还有节点,没遍历完
// 条件2:p->next->data != val 下一个节点不是目标值
while (p->next != NULL && p->next->data != val)
p = p->next; // p向后移动
// 退出循环两种情况:
// 情况1:p->next == NULL → 整条链表走完,找不到值val
if (p->next == NULL)
return false; // 删除失败
// 情况2:找到了!p->next 就是要删除的节点
del = p->next; // del指向待删除节点
p->next = del->next; // 前驱节点直接跳过目标节点,连上后面节点(链表断链移除目标)
free(del); // 释放被删除节点的堆内存,防止内存泄漏
return true; // 删除成功
}
// 打印链表
void PrintList(LinkList L)
{
LNode *p = L->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
LinkList L;
InitList(L);
// 快速构建链表 10 20 30
TailInsert(L, 10);
TailInsert(L, 20);
TailInsert(L, 30);
printf("原链表:");
PrintList(L);
DeleteByValue(L, 20);
printf("删除20后:");
PrintList(L);
return 0;
}
// 原链表:10 20 30
// 删除20后:10 30
4、链表反转,输出反转后的链表
cpp
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 初始化链表,带头结点
bool InitList(LinkList &L)
{
L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;
return L != NULL;
}
// 尾插法
bool TailInsert(LinkList &L, ElemType val)
{
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = val;
s->next = NULL;
LNode *p = L;
while (p->next != NULL)
p = p->next;
p->next = s;
return true;
}
// 链表反转
void ReverseList(LinkList &L)
{
// 边界判断:空链表 / 只有1个数据节点,无需反转,直接退出
if (L->next == NULL || L->next->next == NULL)
return;
LNode *pre = NULL; // 前驱节点
LNode *cur = L->next; // cur指向第一个有效数据节点(10)
LNode *next; // 临时保存下一个节点,防止断链
while (cur != NULL) // cur遍历到NULL结束
{
next = cur->next; // ①先存好后面节点地址!防止断链
cur->next = pre; // ②当前节点反向,指向前驱
pre = cur; // ③pre往前走一步
cur = next; // ④cur往前走一步
}
// 循环结束:pre指向原链表最后一个节点(30)
L->next = pre; // 头结点接入新的第一个节点
}
// 打印链表
void PrintList(LinkList L)
{
LNode *p = L->next;
while (p != NULL)
{
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
int main()
{
LinkList L;
InitList(L);
TailInsert(L, 10);
TailInsert(L, 20);
TailInsert(L, 30);
printf("原链表:");
PrintList(L);
ReverseList(L);
printf("反转链表后:");
PrintList(L);
return 0;
}
5、链表求长度、查找指定数值节点
cpp
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct LNode
{
ElemType data;
struct LNode *next;
} LNode, *LinkList;
// 1. 获取链表长度
int ListLength(LinkList L)
{
int len = 0;
LNode *p = L;
while (p->next != NULL)
{
len++;
p = p->next;
}
return len;
}
// 2. 按值查找,找到返回结点指针;找不到返回NULL
LNode *LocateElem(LinkList L, ElemType val)
{
LNode *p = L->next;
while (p != NULL && p->data != val)
{
p = p->next;
}
return p;
}
// 初始化带头结点单链表
LinkList InitList()
{
LinkList L = (LNode *)malloc(sizeof(LNode));
L->next = NULL;
return L;
}
// 尾插
void TailInsert(LinkList L, ElemType val)
{
LNode *s = (LNode *)malloc(sizeof(LNode));
s->data = val;
s->next = NULL;
LNode *p = L;
while (p->next != NULL)
p = p->next;
p->next = s;
}
int main()
{
LinkList L = InitList();
TailInsert(L, 10);
TailInsert(L, 20);
TailInsert(L, 30);
printf("链表长度 = %d\n", ListLength(L));
ElemType target = 20;
LNode *res = LocateElem(L, target);
if (res != NULL)
printf("找到数值%d\n", res->data);
else
printf("未找到\n");
return 0;
}
//链表长度 = 3
//找到数值20
6、数组栈、链表栈两种方式实现:push 入栈、pop 出栈
数组栈
cpp
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
typedef int ElemType;//重命名
// 顺序栈定义
typedef struct
{
ElemType data[MAXSIZE];
int top;
} SqStack;
// 初始化
void InitSqStack(SqStack *s)
{
s->top = -1;
}
// 入栈
int Push(SqStack *s, ElemType val)
{
if (s->top >= MAXSIZE - 1)
{
printf("栈满!\n");
return 0;
}
s->data[++s->top] = val;
return 1;
}
// 出栈
int Pop(SqStack *s, ElemType *res)
{
if (s->top == -1)
{
printf("栈空!\n");
return 0;
}
*res = s->data[s->top--];
return 1;
}
int main()
{
SqStack st;
InitSqStack(&st);
Push(&st, 10);
Push(&st, 20);
Push(&st, 30);
ElemType num;
Pop(&st, &num);
printf("出栈元素:%d\n", num);
Pop(&st, &num);
printf("出栈元素:%d\n", num);
Pop(&st, &num);
printf("出栈元素:%d\n", num);
Pop(&st, &num);
return 0;
}
链表栈
cpp
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;//重命名
//定义结点
typedef struct StackNode{
ElemType data;
struct StackNode *next;
}StackNode, *LinkStack;
//初始化:创建头结点
void InitLinkStack(LinkStack *S){
*S = (StackNode*)malloc(sizeof(StackNode));
(*S)->next = NULL; //头结点后继置空
}
//入栈(头插,头结点后面是栈顶)
int LinkPush(LinkStack S, ElemType val){
StackNode *p = (StackNode*)malloc(sizeof(StackNode));
if(p == NULL) return 0;
p->data = val;
p->next = S->next;
S->next = p;
return 1;
}
//出栈
int LinkPop(LinkStack S, ElemType *res){
//判断栈空:头结点后面没有元素
if(S->next == NULL){
printf("栈空!\n");
return 0;
}
StackNode *p = S->next; //p指向栈顶结点
*res = p->data;
S->next = p->next;
free(p);
return 1;
}
int main()
{
LinkStack S;
InitLinkStack(&S);
LinkPush(S, 11);
LinkPush(S, 22);
LinkPush(S, 33);
ElemType val;
LinkPop(S, &val);
printf("出栈:%d\n", val);
LinkPop(S, &val);
printf("出栈:%d\n", val);
LinkPop(S, &val);
printf("出栈:%d\n", val);
LinkPop(S, &val);
return 0;
}
| 对比项目 | 顺序栈(数组栈) | 链栈【带头结点】 |
|---|---|---|
| 结构核心 | 数组 + top 下标 | 头结点 (无数据),head->next 为栈顶 |
| 空栈条件 | top = -1 |
head->next == NULL |
| 栈满条件 | top == MAXSIZE-1,会溢出 |
无容量上限 |
| Push 入栈逻辑 | 1. 检查栈满2.++top3.data[top]=值 |
1. 新建结点 p2.p->next = head->next3.head->next = p(头插) |
| Pop 出栈逻辑 | 1. 检查栈空2. 取出data[top]3.top-- |
1. 检查栈空 head->next==NULL2.p 指向栈顶结点 p=head->next3. 取值4.head->next = p->next5.free(p) |
| 内存行为 | 只移动下标,数组数据残留 | 动态 malloc/free,结点销毁 |
| 时间复杂度 | O(1) | O(1) |