线 性 数 据 结 构 双 雄:栈 与 队 列 的 原 理、实 现 与 应 用

线 性 数 据 结 构 双 雄:栈 与 队 列 的 原 理、实 现 与 应 用

  • [栈 的 操 作 实 现](#栈 的 操 作 实 现)
    • [代 码 全 貌 与 功 能 介 绍](#代 码 全 貌 与 功 能 介 绍)
    • [代 码 效 果 展 示](#代 码 效 果 展 示)
  • [队 列](#队 列)
  • [队 列 的 操 作 实 现](#队 列 的 操 作 实 现)
    • [代 码 全 貌 与 功 能 介 绍](#代 码 全 貌 与 功 能 介 绍)
    • [代 码 效 果 展 示](#代 码 效 果 展 示)
  • [栈 与 队 列 的 对 比 分 析](#栈 与 队 列 的 对 比 分 析)
  • [总 结 与 进 阶 建 议](#总 结 与 进 阶 建 议)
    • [核 心 知 识 点 回 顾](#核 心 知 识 点 回 顾)
    • [学 习 进 阶 建 议](#学 习 进 阶 建 议)
    • [总 结](#总 结)

💻作 者 简 介:曾 与 你 一 样 迷 茫,现 以 经 验 助 你 入 门 数据 结 构。

💡个 人 主 页:@笑口常开xpr 的 个 人 主 页

📚系 列 专 栏:硬 核 数 据 结 构 与 算 法

✨代 码 趣 语:栈 如 弹 夹,后 进 先 出;队 似 排 队,先 进 先 出。

💪代 码 千 行,始 于 坚 持,每 日 敲 码,进 阶 编 程 之 路。

📦gitee 链 接:gitee

在 数 据 结 构 的 世 界 里,每 一 种 设 计 都 可 能 孕 育 出 惊 人 的 效 率 变 革。你 是 否 深 思 过,一 组 精 心 组 织 的 数 据 究 竟 能 创 造 怎 样 的 奇 迹?每 一 次 挖 掘 底 层 原 理,都 是 与 计 算 机 智 慧 的 巅 峰 对 话;每 一 次 剖 析 存 储 模 式,都 在 破 解 数 据 世 界 的 终 极 密 码。准 备 好 迎 接 这 场 盛 宴 了 吗?让 我 们 一 同 探 寻 栈 和 队 列 的 无 尽 奥 秘,见 证 它 如 何 重 塑 数 字 时 代 的 运 行 法 则!



定 义

栈 是 一 种 特 殊 的 线 性 表,其 只 允 许 在 固 定 的 一 端 (栈 顶)进 行 插 入 和 删 除 元 素 操 作。


基 本 概 念

栈 顶

进 行 数 据 插 入 和 删 除 操 作 的 一 端 称 为 栈 顶。

栈 底

另 一 端 称 为 栈 底。

入 栈

栈 的 插 入 操 作 叫 做 进 栈 / 压 栈 / 入 栈,数 据 从 栈 顶 进 入。将 一 个 元 素 添 加 到 栈 顶,当 执 行 入 栈 操 作 时,栈 顶 指 针 向 上 移 动 一 位,指 向 新 加 入 的 元 素。

出 栈

栈 的 删 除 操 作 叫 做 出 栈,数 据 从 栈 顶 删 除。移 除 并 返 回 栈 顶 的 元 素,出 栈 后,栈 顶 指 针 向 下 移 动 一 位,指 向 栈 中 的 下 一 个 元 素。


原 则

栈 中 的 数 据 元 素 遵 守 后 进 先 出 或 者 先 进 后 出 的 原 则。即 最 后 入 栈 的 元 素 会 先 出 栈,最 先 入 栈 的 元 素 后 出 栈。

下 面 分 别 以 元 素 为 1234 入 栈 和 出 栈 进 行 动 画 演 示


栈 的 操 作 实 现

代 码 全 貌 与 功 能 介 绍


整 个 栈 由 三 个 主 要 文 件 构 成:stack.h、stack.c 和 test.c。这 种 多 文 件 的 架 构 设 计,有 助 于 将 不 同 功 能 模 块 分 离,提 高 代 码 的 可 读 性、可 维 护 性 与 可 扩 展 性。
stack.h
stack.h 包 含 了 栈 所 需 的 头 文 件 引 用、常 量 定 义 以 及 函 数 声 明。
test.c
test.c 是 栈 的 主 逻 辑 文 件,负 责 处 理 用 户 输 入 和 代 码 流 程 的 控 制。
stack.c
stack.c 则 实 现 了 栈 的 具 体 功 能 函 数。
下 面 展 示完 整 代 码
读 者 可 以 将 这 段 代 码 复 制 到 自 己 的 编 译 器 中 运 行。
stack.h

javascript 复制代码
#pragma once

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
//静态栈
//#define N 10
//struct Stack
//{
//	int a[N];
//	int top;
//};

//动态栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* a;
	int top;
	int capacity;   //容量
}ST;

//初始化
void STInit(ST* ps);

void STDestroy(ST* ps);

void STMiddle(void(*Pf)(ST* ps, STDataType x), ST* ps);

//只能在一端插入,即栈顶
void STPush(ST* ps,STDataType x);

void STPop(ST* ps);

int STSize(ST* ps);

bool STEmpty(ST* ps);

//访问栈顶元素
STDataType STTop(ST* ps);

void STPrint(ST* ps);

//保存栈中的元素到文件中
void STSave(ST* ps);

//从文件中加载
void STLoad(ST* ps);

test.c

javascript 复制代码
#define _CRT_SECURE_NO_WARNINGS 1 

#include "stack.h"
void menu()
{
	printf("***************************************\n");
	printf("*****   0. STExit     1. STPush   *****\n");
	printf("*****   2. STPop      3. STSize   *****\n");
	printf("*****   4. STEmpty    5. STTop    *****\n");
	printf("*****   6. STPrint                *****\n");
	printf("***************************************\n");
}
void test()
{
	int input = 0;
	ST st;
	STInit(&st);
	do
	{
		menu();
		printf("请输入你想要进行的操作:>");
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			STSave(&st);
			STDestroy(&st);
			break;
		case 1:
			STMiddle(STPush, &st);
			break;
		case 2:
			STPop(&st);
			STPrint(&st);
			break;
		case 3:
			printf("%d\n", STSize(&st));
			break;
		case 4:
			if (STEmpty(&st))
			{
				printf("栈为空\n");
			}
			else
			{
				printf("栈不为空\n");
			}
			break;
		case 5:
			printf("栈顶元素是:%d\n", STTop(&st));
			break;
		case 6:
			STPrint(&st);
			break;
		default:
			printf("输入无效,请重新输入\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

stack.c

javascript 复制代码
#define _CRT_SECURE_NO_WARNINGS 1 

#include "stack.h"

void STInit(ST* ps)
{
	assert(ps);
	ps->a = (STDataType*)malloc(sizeof(STDataType) * 4);
	if (ps->a == NULL)
	{
		perror("ps->a");
		return;
	}
	ps->capacity = 4;
	ps->top = 0;          //top是栈顶元素的下一个位置
	//ps->top = -1;         //top是栈顶元素
	STLoad(ps);
}

void STDestroy(ST* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->top = 0;
	ps->capacity = 0;
}
void STPush(ST* ps, STDataType x)
{
	assert(ps);
	if (ps->top == ps->capacity)
	{
		STDataType* tmp = (STDataType*)realloc(ps->a, sizeof(STDataType) * ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
	ps->a[ps->top] = x;
	ps->top++;
}

void STPop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	ps->top--;
}

int STSize(ST* ps)
{
	assert(ps);
	return ps->top;
}

bool STEmpty(ST* ps)
{
	assert(ps);
	return ps->top == 0;
}

STDataType STTop(ST* ps)
{
	assert(ps);
	assert(!STEmpty(ps));
	return ps->a[ps->top - 1];
}


void STPrint(ST* ps)
{
	assert(ps);
	int i = 0;
	while (i < ps->top)
	{
		printf("%d ", ps->a[i]);
		i++;
	}
	printf("\n");
}
void STSave(ST* ps)
{
	assert(ps);
	FILE* pf = fopen("stack.txt", "w");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}
	int i = 0;
	for (i = 0;i < ps->top;i++)
	{
		fprintf(pf, "%d ", ps->a[i]);
	}
	fclose(pf);
	pf = NULL;
	printf("保存数据成功\n");
}

void STLoad(ST* ps)
{
	assert(ps);
	FILE* pf = fopen("stack.txt", "r");
	if (pf == NULL)
	{
		perror("fopen fail");
		return;
	}
	int data = 0;
	while (fscanf(pf, "%d", &data) == 1)
	{
		STPush(ps, data);
	}
	fclose(pf);
	pf = NULL;
}
void STMiddle(void(*pf)(ST* ps, STDataType x),ST* ps)
{
	assert(ps);
	int x = 0;
	printf("请输入你想要插入的数字:>");
	scanf("%d", &x);
	pf(ps, x);
	STPrint(ps);
}

代 码 效 果 展 示

菜 单 展 示

每 次 循 环 开 始 时 会 显 示 菜 单,内 容 包 括:
STExit :退 出 程 序 并 将 栈 中 的 元 素 保 存 到 文 件 中
STPush :入 栈
STPop :出 栈
SLSize :栈 中 元 素 的 个 数
STEmpty :栈 是 否 为 空
STTop :栈 顶 元 素
STPrint:输 出 栈 中 的 元 素

退 出 栈(STExit)

输 入 0 后,程 序 会 将 栈 中 的 信 息 保 存 到 文 件 "stack.txt" 中。释 放 内 存 并 销 毁 栈, 然 后 退 出 程 序。

入 栈(STPush)

输 入 1 后,程 序 会 提 示 用 户 输 入 插 入 的 数 字。输 入 完 成 后,数 字 被 添 加 到 栈,然 后 输 出 修 改 后 的 栈。


出 栈(STPop)

输 入 2 后,先 入 栈 的 数 字 会 被 删 除,然 后 输 出 修 改 后 的 栈。

栈 中 有 效 元 素 个 数(STSize)

输 入 3 后,程 序 会 输 出 栈 中 的 元 素 个 数。


检 查 栈 是 否 为 空(STEmpty)

输 入 4 后,程 序 会 检 查 栈 是 否 为 空,如 果 栈 为 空,则 输 出 栈 是 空,反 之,则 输 出 栈 不 为 空。

输 出 栈 顶 元 素(STTop)

输 入 5 后,程 序 会 输 出 栈 顶 元 素。

输 出 栈 中 的 元 素(STPrint)

输 入 6 后,程 序 会 在 屏 幕 上 显 示 目 前 已 经 保 存 的 栈 中 的 元 素。


队 列


定 义

队 列 是 一 种 线 性 表。队 列 只 允 许 在 线 性 表 的 一 端 进 行 插 入 元 素,而 在 另 一 端 删 除 元 素。


基 本 概 念
队 尾

队 列 中 允 许 插 入 的 一 端 被 称 作 队 尾。

队 头

队 列 中 允 许 删 除 的 一 端 被 称 作 队 头。

出 队

出 队 是 从 队 列 的 头 部 移 除 并 返 回 一 个 元 素 的 操 作。

入 队

入 队 是 将 一 个 新 元 素 添 加 到 队 列 的 尾 部 的 操 作。

队 空

队 列 中 没 有 元 素

队 满

队 列 中 元 素 数 量 达 到 上 限

原 则

队 列 是 一 种 遵 循 先 进 先 出 或 者 后 进 后 出 原 则 的 重 要 数 据 结 构。

队 列 的 操 作 实 现

代 码 全 貌 与 功 能 介 绍


整 个 队 列 由 三 个 主 要 文 件 构 成:Queue.h、Queue.c 和 test.c。这 种 多 文 件 的 架 构 设 计,有 助 于 将 不 同 功 能 模 块 分 离,提 高 代 码 的 可 读 性、可 维 护 性 与 可 扩 展 性。

Queue.h

Queue.h 包 含 了 队 列 所 需 的 头 文 件 引 用、常 量 定 义 以 及 函 数 声 明。

test.c

test.c 是 队 列 的 主 逻 辑 文 件,负 责 处 理 用 户 输 入 和 代 码 流 程 的 控 制。

Queue.c

Queue.c 则 实 现 了 队 列 的 具 体 功 能 函 数。

下 面 展 示完 整 代 码
读 者 可 以 将 这 段 代 码 复 制 到 自 己 的 编 译 器 中 运 行。

Queue.h

javascript 复制代码
#include<stdio.h>
#include<stdbool.h>
#include<assert.h>
#include<stdlib.h>

typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

//初始化队列
void QueueInit(Queue* pq);

//销毁队列
void QueueDestory(Queue* pq);

//队尾入队列
void QueuePush(Queue* pq,QDataType x);

//队头出队列
void QueuePop(Queue* pq);

//获取队列中有效元素个数
int QueueSize(Queue* pq);

//检查队列是否为空
bool QueueEmpty(Queue* pq);

//取出队头的数据
QDataType QueueFront(Queue* pq);

//取出队尾的数据
QDataType QueueBack(Queue* pq);

//输出队列
void QueuePrint(Queue* pq);

void QueueMiddlePush(void(*pf)(Queue* pq, QDataType x), Queue* pq);

void QueueMiddle(Queue* pq, int num);

//保存队列到文件中
void QueueSave(Queue* pq);

//从文件中加载队列
void QueueLoad(Queue* pq);

test.c

javascript 复制代码
#define _CRT_SECURE_NO_WARNINGS 1 
#include"Queue.h"
void menu()
{
	printf("**********************************************\n");
	printf("*****   0. QueueExit    1.  QueuePush    *****\n");
	printf("*****   2. QueuePop     3.  QueueSize    *****\n");
	printf("*****   4. QueueFront   5.  QueueBack    *****\n");
	printf("*****   6. QueueEmpty   7.  QueuePrint   *****\n");
	printf("**********************************************\n");
}
void test()
{
	int input = 0;
	Queue q;
	QueueInit(&q);
	do
	{
		menu();
		printf("请输入你想要进行的操作:>");
		scanf("%d", &input);
		switch (input)
		{
		case 0:
			QueueSave(&q);
			QueueDestory(&q);
			break;
		case 1:
			QueueMiddlePush(QueuePush, &q);
			break;
		case 2:
			QueueMiddle(&q, 2);
			break;
		case 3:
			printf("队列元素个数:%d\n", QueueSize(&q));
			break;
		case 4:
			QueueMiddle(&q, 4);
			break;
		case 5:
			QueueMiddle(&q, 5);
			break;
		case 6:
			QueueMiddle(&q, 6);
			break;
		case 7:
			QueuePrint(&q);
			break;
		default:
			printf("输入无效,请重新输入\n");
			break;
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

Queue.c

javascript 复制代码
#define _CRT_SECURE_NO_WARNINGS 1 

#include "Queue.h"

void QueueInit(Queue* pq)
{
	assert(pq);
	pq->head = pq->tail = NULL;
	pq->size = 0;
	QueueLoad(pq);
}

void QueueDestory(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->head = pq->tail = NULL;
	pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("newnode");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	if (pq->head == NULL)
	{
		assert(pq->tail == NULL);
		pq->head = pq->tail = newnode;
	}
	else
	{
		pq->tail->next = newnode;
		pq->tail = newnode;
	}
	pq->size++;
}

void QueuePop(Queue* pq)
{
	assert(pq);
	assert(pq->head != NULL);
	//方法1
	//QNode* next = pq->head->next;
	//free(pq->head);
	//pq->head = next;
	//if (pq->head == NULL)
	//{
	//	pq->tail = NULL;
	//}
	//方法2
	if (pq->head->next == NULL)
	{
		free(pq->head);
		pq->tail = pq->head = NULL;
	}
	else
	{
		QNode* next = pq->head->next;
		free(pq->head);
		pq->head = next;
	}
	pq->size--;
}
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	//return pq->size == 0;
	return pq->head == NULL && pq->tail == NULL;
}

QDataType QueueFront(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}

QDataType QueueBack(Queue* pq)
{
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}

void QueuePrint(Queue* pq)
{
	assert(pq);
	QNode* cur = pq->head;
	if (QueueEmpty(pq))
	{
		printf("队列为空\n");
		return;
	}
	else
	{
		while (cur)
		{
			printf("%d ", cur->data);
			cur = cur->next;
		}
		printf("\n");
	}
}
void QueueMiddlePush(void(*pf)(Queue* pq, QDataType x), Queue* pq)
{
	int x = 0;
	printf("请输入你想要插入的元素:>");
	scanf("%d", &x);
	pf(pq, x);
	QueuePrint(pq);
}

void QueueMiddle(Queue* pq, int num)
{
	if (num == 2)
	{
		if (QueueEmpty(pq))
		{
			printf("队列已空,无法出队\n");
		}
		else
		{
			printf("出队元素:%d\n", QueueFront(pq));
			QueuePop(pq);
		}
	}
	else if (num == 4)
	{
		if (QueueEmpty(pq))
		{
			printf("队列已空,无队头元素\n");
		}
		else
		{
			printf("队头元素:%d\n", QueueFront(pq));
		}
	}
	else if (num == 5)
	{
		if (QueueEmpty(pq))
		{
			printf("队列已空,无队尾元素\n");
		}
		else
		{
			printf("队尾元素:%d\n", QueueBack(pq));
		}
	}
	else
	{
		if (QueueEmpty(pq))
		{
			printf("队列已空\n");
		}
		else
		{
			printf("队列不为空\n");
		}
	}
}

void QueueSave(Queue* pq)
{
	assert(pq);
	FILE* pf = fopen("queue.txt", "w");
	if (pf == NULL)
	{
		perror("无法打开文件");
		return;
	}
	QNode* cur = pq->head;
	while (cur)
	{
		fprintf(pf, "%d ", cur->data);
		cur = cur->next;
	}
	fclose(pf);
	pf = NULL;
	printf("保存文件成功\n");
}

void QueueLoad(Queue* pq)
{
	assert(pq);
	FILE* pf = fopen("queue.txt", "r");
	if (pf == NULL)
	{
		// 文件不存在或无法打开,可能是第一次运行
		return;
	}
	int data = 0;
	while (fscanf(pf, "%d", &data) != EOF)
	{
		QueuePush(pq, data);
	}
	fclose(pf);
	pf = NULL;
}

代 码 效 果 展 示

菜 单 展 示

每 次 循 环 开 始 时 会 显 示 菜 单,内 容 包 括:
QueueExit :退 出 程 序 并 将 队 列 元 素 保 存 到 文 件 中
QueuePush :入 队 列
QueuePop :出 队 列
QueueSize :获 取 队 列 中 有 效 元 素 个 数
QueueFront :取 出 队 头 的 数 据
QueueBack :取 出 队 尾 的 数 据
QueueEmpty :检 查 队 列 是 否 为 空
QueuePrint:输 出 队 列 元 素

退 出 程 序(QueueExit)

输 入 0 后,程 序 会 将 队 列 中 的 信 息 保 存 到 文 件 "queue.txt" 中。释 放 内 存 并 销 毁 队 列, 然 后 退 出 程 序。

入 队 列(QueuePush)

输 入 1 后,程 序 会 提 示 用 户 输 入 插 入 的 数 字。输 入 完 成 后,数 字 被 添 加 到 队 列 的 末 尾,然 后 输 出 修 改 后 的 队 列。

出 队 列(QueuePop)

输 入 2 后,队 列 的 头 部 的 数 字 会 被 删 除,并 输 出 删 除 的 元 素(出 队 的 元 素)。

队 列 中 有 效 元 素 个 数(QueueSize)

输 入 3 后,程 序 会 输 出 队 列 中 的 元 素 个 数。

取 出 队 头 元 素(QueueFront)

输 入 4 后,程 序 会 输 出 队 列 的 头 部 元 素(队 列 的 第 一 个 元 素)。

取 出 队 尾 元 素(QueueBack)

输 入 5 后,程 序 会 输 出 队 列 的 尾 部 元 素(队 列 的 最 后 一 个 元 素)。

检 查 队 列 是 否 为 空(QueueEmpty)

输 入 6 后,程 序 会 检 查 队 列 是 否 为 空,如 果 队 列 为 空,则 输 出 队 列 是 空,如 果 队 列 不 为 空,则 输 出 队 列 不 为 空。

输 出 队 列 元 素(QueuePrint)

输 入 7 后,程 序 会 在 屏 幕 上 显 示 目 前 已 经 保 存 的 队 列 元 素。



栈 与 队 列 的 对 比 分 析

对比 栈(Stack) 队列(Queue)
操作限制 仅在栈顶进行插入和删除 队尾插入,队头删除
数据原则 后进先出 先进先出
典型操作 Push(入栈)、Pop(出栈) Enqueue(入队)、Dequeue(出队)
实现方式 数组或链表 数组或链表(通常链表更优)
内存管理 通常需要考虑扩容 链表实现时动态分配节点

总 结 与 进 阶 建 议

核 心 知 识 点 回 顾

1、栈 是 一 种 先 进 后 出 的 数 据 结 构,所 有 操 作 集 中 在 栈 顶,适 合 需 要 "回 退" 逻 辑 的 场 景。

2、队 列 是 一 种 先 进 先 出 的 数 据 结 构,插 入 在 队 尾,删 除 在 队 头,适 合 需 要 保 持 顺 序 的 场 景。

3、两 者 都 是 线 性 数 据 结 构,但 操 作 方 式 截 然 不 同。

4、代 码 实 现 上,栈 可 以 用 数 组 或 链 表,队 列 更 倾 向 于 链 表 实 现 以 避 免 "假 溢 出"。

学 习 进 阶 建 议

深 入 理 解 原 理 :尝 试 分 析 不 同 场 景 下 栈 和 队 列 的 效 率 差 异。
拓 展 实 现 方 式:尝 试 用 不 同 数 据 结 构 实 现 栈 和 队 列 (如 双 向 循 环 链 表)。

总 结

至 此,关 于 栈 和 队 列 的 探 索 暂 告 一 段 落,但 你 的 编 程 征 程 才 刚 刚 启 航。编 写 代 码 是 与 计 算 机 逻 辑 深 度 对 话,过 程 中 虽 会 在 结 构 设 计、算 法 实 现 的 困 境 里 挣 扎,但 这 些 磨 砺 加 深 了 对 代 码 逻 辑 和 数 据 组 织 的 理 解。愿 你 合 上 电 脑 后,灵 感 不 断,在 数 据 结 构 的 世 界 里 持 续 深 耕,书 写 属 于 自 己 的 编 程 传 奇,下 一 次 开 启,定 有 全 新 的 精 彩 等 待。小 编 期 待 重 逢,盼 下 次 阅 读 时 见 证 你 们 更 大 的 进 步,共 赴 代 码 之 约!

相关推荐
怀旧,1 小时前
【数据结构】7. 栈和队列
数据结构
W说编程3 小时前
算法导论第一章:算法基础与排序艺术
c语言·数据结构·算法
titan TV man3 小时前
上海市计算机学会竞赛平台2022年5月月赛丙组最远城市距离
数据结构·算法
慢半拍iii12 小时前
数据结构——D/串
c语言·开发语言·数据结构·c++
怀旧,12 小时前
【数据结构】5. 双向链表
数据结构·windows·链表
会不再投降21912 小时前
《算法复杂度:数据结构世界里的“速度与激情”》
数据结构·算法
vvilkim12 小时前
深入解析 Pandas 核心数据结构:Series 与 DataFrame
数据结构·pandas
Frankabcdefgh12 小时前
Python基础数据类型与运算符全面解析
开发语言·数据结构·python·面试
wangjialelele13 小时前
动态内存管理之柔性数组
数据结构·算法
南枝异客13 小时前
三数之和-力扣
开发语言·javascript·数据结构·算法·leetcode·排序算法