❤️[数据结构]动图+万字详解栈和队列(动图+实例)建议收藏❤️(代码片段)

Linux猿 Linux猿     2023-01-07     674

关键词:


🎈 作者:Linux猿

🎈 简介:CSDN博客专家🏆,华为云享专家🏆,C/C++、面试、刷题、算法尽管咨询我,关注我,有问题私聊!

🎈 关注专栏:C/C++面试通关集锦 (优质好文持续更新中……)🚀

🎈 欢迎小伙伴们点赞👍、收藏⭐、留言💬


目录

一、栈

1.1 什么是栈

1.2 实现方式

1.3 数组实现栈

1.3.0 类封装

1.3.1 push 操作

1.3.2 pop 操作

1.3.3 empty 操作

1.3.4 top 操作

1.3.5 size 操作

1.3.6 数组栈测试

1.4 链表实现栈

1.4.0 类封装

1.4.1 push 操作

1.4.2 pop 操作

1.4.3 empty 操作

1.4.4 top 操作

1.4.5 size 操作

1.4.6 链表栈测试

1.5 实战分析

1.6 复杂度分析

1.6.1 时间复杂度

1.6.2 空间复杂度

1.7 栈的应用

二、队列

2.1 什么是队列

2.2 实现方式

2.3 数组实现队列

2.3.0 类封装

2.3.1 push 操作

2.3.2 pop 操作

2.3.3 front 操作

2.3.4 empty 操作

2.3.5 size 操作

2.3.6 back 操作

2.3.7 数组队列测试

2.4 链表实现队列

2.4.0 类封装

2.4.1 push 操作

2.4.2 pop 操作

2.4.3 front 操作

2.4.4 empty 操作

2.4.5 size 操作

2.4.6 链表队列测试

2.5 实战分析

2.6 复杂度分析

 2.6.1 时间复杂度

2.6.2 空间复杂度

2.7 队列的应用

三、总结


在日常的学习以及求职面试中,栈和队列是一块非常重要的内容,经常被提及,本篇文章总结了栈和队列基本概念及常用操作,并且分别使用数组和链表实现了栈和队列,简单易懂,想不会都难!赶紧来看下吧!

一、栈

1.1 什么是栈

栈是一种抽象数据结构,也是一种线性数据结构,具有后进先出(LIFO,Last In First Out)的特性,即:后进入栈中的元素在先进入元素的上面,故后进入栈中的元素先出栈,当然也可以说是先进后出,即:先进入的元素后出栈,一样的原理,只是说法不同。如下图所示:

 从上图可以看到,栈只有一个口,即是入口也是出口,后进入栈的元素 C,比先进入栈的 B 和 A 先出栈,这就是所谓的后进先出。如上图所示,栈有栈顶和栈底。

来看一下动图,如下所示:

标题

1.2 实现方式

栈的实现可以通过数组或链表来实现,如下图所示:

标题
标题

 下面分别来看一下数组和链表来实现栈。

1.3 数组实现栈

1.3.0 类封装

下面用类封装了栈的常用操作,如下所示:

#define NUM 100000 // 栈的大小
class Stack 
    int data[NUM];  // 数组模拟栈
    int num;    // 栈指针,指向栈顶元素
public:
    Stack()    // 初始化
        num = -1;
        memset(data, 0, sizeof(data));
    
    void push(int val); // 添加元素
    int pop();          // 删除栈顶元素
    int top();          // 返回栈顶元素
    bool empty();       // 判断是否为空
    int size();         // 栈大小
;

上面是以 int 为例子,更好的封装是使用 C++ 的模板,这里为了便于理解采用了更简单的方式。

另一方面,数组还可以改成动态分配的形式,即:先分配一个初始数组,如果栈溢出了,则重新分配,将原先的内容拷贝到新分配的数组中,分配的方式可以参考 STL 的递增策略。

1.3.1 push 操作

向栈中添加元素,如下所示:

void Stack::push(int val) 
    if(num >= NUM) 
        cout<<"Stack Overflow!"<<endl;
        return;
    
    data[++num] = val;

如上所示,先判断栈是否已满,未满则添加元素。可以将上面的 if 语句里的内容修改为增加栈容量。

1.3.2 pop 操作

删除栈顶元素,因为栈是后进先出的,如下所示:

int Stack::pop() 
    if(empty()) 
        cout<<"Stack Empty!"<<endl;
        return -1;
    
    return data[num--];

如上所示,先判断栈是否为空,不空则删除栈顶元素,只要栈顶指针移动即可。

1.3.3 empty 操作

判断栈是否为空,空返回 true,否则返回 false ,如下所示:

bool Stack::empty() 
    return num == -1;

这里也许有人会说“为啥不用 int 类型,返回 0 和 1 呢? 用 true 和 false 更好是因为 bool 类型占一个字节,而 int 通常占 4 个字节。

1.3.4 top 操作

返回栈顶元素,如下所示:

int Stack::top() 
    if(empty()) 
        cout<<"Stack Empty!"<<endl;
        return -1;
    
    return data[num];

先判断栈是否为空,如果非空则返回栈顶元素。

注意:这里不是删除,仅仅是返回栈顶元素的值。

1.3.5 size 操作

返回栈大小,如下所示:

int Stack::size() 
    return num + 1;

栈指针 num 是从 0 开始的,故返回 num+1。

1.3.6 数组栈测试

下面是测试上面的数组栈实现,如下所示:

int main()

    Stack st;

    st.push(10);
    st.push(20);
    cout<<"The size of stack is "<<st.size()<<endl;
    cout<<"The top of stack is "<<st.top()<<endl;
    cout<<"The stack empty is "<<st.empty()<<endl;
    cout<<"----------------------------------------"<<endl;

    st.pop();
    cout<<"The size of stack is "<<st.size()<<endl;
    cout<<"The top of stack is "<<st.top()<<endl;
    cout<<"----------------------------------------"<<endl;
    return 0;

输出为:

The size of stack is 2
The top of stack is 20
The stack empty is 0
----------------------------------------
The size of stack is 1
The top of stack is 10
----------------------------------------

1.4 链表实现栈

1.4.0 类封装

使用类封装栈,如下所示:

struct node  // 链表单个节点
    int val;  // 存储栈元素值
    struct node* next;// 指向下一个元素的指针
    node(int value)  // 赋初值
        val = value;
    
;

class Stack 
    struct node *index; // 指向栈顶元素
    int s_size; // 记录栈容量
public:
    Stack()  // 初始化
        index = nullptr;
        s_size = 0;
    
    ~Stack() ;
    void push(int val); // 添加元素
    int pop();          // 删除栈顶元素
    int top();          // 返回栈顶元素
    bool empty();       // 判断是否为空
    int size();         // 栈大小
;

struce node 是链表中的单个元素, class Stack 包含栈的各种操作,这里使用 s_size 记录栈的容量,便于操作。当然,这里是以 int 为例,可以将其修改为 C++ 的模板形式。

1.4.1 push 操作

向栈中添加元素,如下所示:

void Stack::push(int val) 
    struct node* tmp = new node(val);
    if(tmp == nullptr) 
        cout<<"Failed to allocate space!"<<endl;
        return;
    
    tmp->next = index;
    index = tmp;
    s_size++;

如上所示,这里不用判断栈是否已满,需要判断一个是否分配成功。

1.4.2 pop 操作

删除栈顶元素,因为栈是后进先出的,如下所示:

int Stack::pop() 
    if(empty()) 
        cout<<"Stack Empty!"<<endl;
        return -1;
    
    int tmpVal = index->val; // 暂存栈顶元素
    index = index->next; // 删除栈顶元素
    s_size--;            // 栈元素个数减一
    return tmpVal; // 这个返回下栈顶元素

如上所示,先判断栈是否为空,不空则删除栈顶元素,只要栈顶指针移动即可。

1.4.3 empty 操作

判断栈是否为空,空返回 true,否则返回 false ,如下所示:

bool Stack::empty() 
    return index == nullptr;

1.4.4 top 操作

返回栈顶元素,如下所示:

int Stack::top() 
    if(empty()) 
        cout<<"Stack Empty!"<<endl;
        return -1;
    
    return index->val; // 仅仅返回栈顶元素

因为 index 一直指向栈顶元素,所以直接返回 index->val。

1.4.5 size 操作

返回栈大小,如下所示:

int Stack::size() 
    return s_size;

这里使用 s_size 记录栈大小,不然每次都要遍历链表。

1.4.6 链表栈测试

下面是测试上面的链表栈实现,如下所示:

int main()

    Stack st;

    st.push(10);
    st.push(20);
    cout<<"The size of stack is "<<st.size()<<endl;
    cout<<"The top of stack is "<<st.top()<<endl;
    cout<<"The stack empty is "<<st.empty()<<endl;
    cout<<"----------------------------------------"<<endl;

    st.pop();
    cout<<"The size of stack is "<<st.size()<<endl;
    cout<<"The top of stack is "<<st.top()<<endl;
    cout<<"----------------------------------------"<<endl;
    return 0;

输出为:

linuxy@linuxy:~/Stack$ g++ -o main Stack.cpp 
linuxy@linuxy:~/Stack$ ./main 
The size of stack is 2
The top of stack is 20
The stack empty is 0
----------------------------------------
The size of stack is 1
The top of stack is 10
----------------------------------------
linuxy@linuxy:~/Stack$ 

1.5 实战分析

模拟元素栈操作,如何实现从下面的入栈顺序到出栈顺序。

入栈顺序:A B C D

出栈顺序:C B D A

如上所示,需要找到一种方法,实现从入站次序到出站次序,这是栈经常考的题目,步骤如下:

(1)因为第一个出站的是 C,所以 A,B ,C依次入栈;

(2)这时,C 在栈顶,C 出栈;

(3)因为第二个出栈的是 B,当前栈顶为 B,所以直接让 B 出栈;

(4)B 出栈后,当前栈顶为 A,但是,应该是 D 出栈,所以先让 D 进栈;

(5)当前栈顶为 D,下一个出栈元素为 D,让 D 出栈;

(6)当前栈顶元素为 A,下一个出栈元素对应 A,所以 A 出栈;

下面来看下动图:

1.6 复杂度分析

1.6.1 时间复杂度

不管是链表实现的栈,还是数组实现的栈,push 和 pop 操作的时间复杂度都是O(1)的,链表实现的栈中 clear 操作是O(n)的,因为需要释放所有的链表空间,其它操作都是O(1)的。

1.6.2 空间复杂度

链表相对于数组更节省空间,因为链表使用到才会分配,数组是提前分配好,而且如果栈满时,数组还需要重新分配。

1.7 栈的应用

(1)深度优先搜索

深度优先搜索的非递归实现通常使用栈作为辅助的数组结构。

(2)软件中的回退和前进功能

(3)拓扑排序

二、队列

2.1 什么是队列

队列是一种线性结构的抽象数据类型,可以实现先进先出(FIFO,First In,First Out),即:先进入的元素,先出队列,可以比喻为日常排队买东西。

如下图所示:

标题

从上图可以看到,队列和栈不同,队列有两个口,而且是一个只允许进入元素,一个只允许出元素,后进入栈的元素C,比先进入栈的 B 和 A 先出栈,这就是所谓的后进先出。如上图所示,栈有栈顶和栈底。

来看一下动图,如下所示:

标题

2.2 实现方式

队列的实现可以通过数组或链表来实现,如下图所示:

标题
标题

2.3 数组实现队列

2.3.0 类封装

下面是使用类封装了队列,如下所示:

#define NUM 100000 // 队列大小
class Queue 
    int data[NUM];  // 数组模拟队列
    int first;      // 头指针,指向队列顶部
    int last;       // 尾指针,指向队列尾部
public:
    Queue()    // 初始化
        first = 0;
        last = 0;
        memset(data, 0, sizeof(data));
    
    void push(int val); // 添加元素
    int pop();          // 删除队列头元素
    int front();        // 返回队列头元素
    bool empty();       // 判断是否为空
    int size();         // 队列大小
    int back();         // 返回队列尾元素
;

data 存储队列数据,first 和 last 分别指向队列头部和尾部。

2.3.1 push 操作

向队列中添加元素,如下所示:

void Queue::push(int val) 
    if(last >= NUM) 
        cout<<"Queue Overflow!"<<endl;
        return;
    
    data[last++] = val;

先判断队列是否已满,未满则添加元素,添加元素只需要移动尾指针即可。

2.3.2 pop 操作

删除队列头元素,如下所示:

int Queue::pop() 
    if(empty()) 
        cout<<"Queue Empty!"<<endl;
        return -1;
    
    return data[first++];

如上所示,先判断队列是否为空,不空则删除队列头元素,只需要头指针 first 移动即可。

2.3.3 front 操作

返回头元素的值,和栈的 top 操作相同的原理,如下所示:

int Queue::front() 
    if(empty()) 
        cout<<"Queue Empty!"<<endl;
        return -1;
    
    return data[first];

先判断队列是否为空,非空则返回头元素。

2.3.4 empty 操作

判断队列是否为空,如下所示:

bool Queue::empty() 
    return first == last;

直接比较 first 与 last 是否相等即可。

2.3.5 size 操作

判断队列元素个数,如下所示:

int Queue::size() 
    return last - first;

使用队列尾指针与头指针之前的举例便是元素个数。

2.3.6 back 操作

返回队列尾元素,如下所示:

int Queue::back() 
    if(empty()) 
        cout<<"Queue Empty!"<<endl;
        return -1;
    
    return data[last-1];

先判断是否为空,不为空则返回 last - 1 所在的元素,因为 last 指向尾元素的下一个位置。

2.3.7 数组队列测试

下面是对上面数组实现的队列的测试,如下所示:

int main()

    Queue que;

    cout<<"The queue empty is "<<que.empty()<<endl;
    cout<<"The size of queue is "<<que.size()<<endl;
    cout<<"----------------------------------------"<<endl;
    que.push(10);
    que.push(20);
    cout<<"The size of queue is "<<que.size()<<endl;
    cout<<"The front of queue is "<<que.front()<<endl;
    cout<<"The queue empty is "<<que.empty()<<endl;
    cout<<"----------------------------------------"<<endl;

    que.pop();
    cout<<"The size of queue is "<<que.size()<<endl;
    cout<<"The front of queue is "<<que.front()<<endl;

    return 0;

输出为:

linuxy@linuxy:~/Stack$ ./main 
The queue empty is 1
The size of queue is 0
----------------------------------------
The size of queue is 2
The front of queue is 10
The queue empty is 0
----------------------------------------
The size of queue is 1
The front of queue is 20
linuxy@linuxy:~/Stack$

2.4 链表实现队列

2.4.0 类封装

struct node    // 链表节点
    int val;    // 链表值
    struct node* next;
    node(int value) 
        val = value;
    
;

class Queue 
    struct node *first; // 指向队列头元素
    struct node *rear;  // 指向队列尾元素
    int s_size;         // 记录队列元素个数
public:
    Queue()  // 初始化
        first = nullptr;
        rear = nullptr;
        s_size = 0;
    
    ~Queue();
    void push(int val);  // 添加元素
    int pop();           // 删除队列头元素
    int front();         // 返回队列头元素
    bool empty();        // 判断是否为空
    int size();          // 队列元素个数
    void back();         // 返回队列尾元素
;

first 指向队列头元素,rear 指向队列尾元素,s_size 记录队列中的元素个数。

2.4.1 push 操作

向队列中添加元素,添加到队列尾部,因为队列是先进先出,如下所示:

void Queue::push(int val) 
    struct node* tmp = new node(val);
    if(tmp == nullptr) 
        cout<<"Failed to allocate space!"<<endl;
        return;
    
    if(rear == nullptr)  // 添加第一个元素
        first = tmp;
        rear = tmp;
        tmp->next = nullptr;
     else               // 已有元素
        rear->next = tmp;
        tmp->next = nullptr;
        rear = tmp;
    

    s_size++;

这里需要先分配空间,第一次添加元素需要将 first 和 rear 都指向该元素,否则添加到尾部即可,别忘记增加 s_size。

2.4.2 pop 操作

删除队列头元素,如下所示:

int Queue::pop() 
    if(empty()) 
        cout<<"Stack Empty!"<<endl;
        return -1;
    
    struct node* tmp = first;
    first = first->next;
    int val = tmp->val;
    delete tmp;

    s_size--;
    return val;

先判断队列是否为空,不为空则移动队列头指针,别忘记释放空间。

2.4.3 front 操作

返回队列头元素的值,并不是删除哦!如下所示:

int Queue::front() 
    if(empty()) 
        cout<<"Stack Empty!"<<endl;
        return -1;
    
    return first->val;

队列的 front 和 栈的 top 原理类似。

2.4.4 empty 操作

判断队列是否为空,如下所示:

bool Queue::empty() 
    return first == nullptr;

2.4.5 size 操作

判断队列元素个数,如下所示:

int Queue::size() 
    return s_size;

这里使用了一个辅助变量 s_size,不然每次求队列元素个数都需要遍历一次链表。

2.4.6 链表队列测试

下面是测试上面的链表队列的实现,如下所示:

int main()

    Queue que;

    cout<<"The queue empty is "<<que.empty()<<endl;
    cout<<"The size of queue is "<<que.size()<<endl;
    cout<<"----------------------------------------"<<endl;

    que.push(10);
    que.push(20);
    cout<<"The size of queue is "<<que.size()<<endl;
    cout<<"The top of queue is "<<que.front()<<endl;
    cout<<"The queue empty is "<<que.empty()<<endl;
    cout<<"----------------------------------------"<<endl;

    que.pop();
    cout<<"The size of queue is "<<que.size()<<endl;
    cout<<"The top of queue is "<<que.front()<<endl;
    cout<<"----------------------------------------"<<endl;

    return 0;

输出结果为:

linuxy@linuxy:~/Queue$ ./main 
The queue empty is 1
The size of queue is 0
----------------------------------------
The size of queue is 2
The top of queue is 10
The queue empty is 0
----------------------------------------
The size of queue is 1
The top of queue is 20
----------------------------------------
linuxy@linuxy:~/Queue$

2.5 实战分析

采用层次遍历的方法遍历如下二叉树:

标题

层次遍历上图的二叉树,即:从上到下一层一层的遍历二叉树的节点,按照这个思路,遍历步骤为:

(1)先访问 1 节点,1节点有两个孩子节点,1 节点出队列后,将 2 和 3 两个节点入队;

(2)访问 2 节点,2 节点出队,2 节点有两个子节点 4 和 5,2 节点出队后,4 和 5 节点入队;

(3)访问 3 节点,3 节点没有子节点,直接出队;

(4)依次访问 4  和 5 节点,这两个节点都没有子节点,所以出队即可。

(5)所有节点按照层次遍历的方式访问完毕!

来看一下动图:

标题

2.6 复杂度分析

 2.6.1 时间复杂度

不管是链表实现的队列,还是数组实现的队列,push、pop、empty、front 等操作的时间复杂度都是O(1)的。

2.6.2 空间复杂度

链表相对于数组更节省空间,因为链表使用到才会分配,数组是提前分配好,而且如果队列满时,数组还需要重新分配。

2.7 队列的应用

(1)广度优先搜索

广度优先搜索的实现通常使用队列作为辅助的数组结构。

(2)在一些资源请求或任务调度中,往往是先来先处理。

三、总结

栈和队列都有很强的特性,栈是后进先出,队列是先进先出,应用在不同的应用场景中。

欢迎关注下方👇👇👇公众号👇👇👇,获取更多优质内容🤞(比心)!

❤️五万字《十大排序算法》动图讲解❤️(建议收藏)(代码片段)

...尔排序十、堆堆排序  今天的内容,将围绕这几张动图来展开。可以大致先简单看一下,这是一个归并排序的动图演示,我会对以上几个排序从算法原理、动图详解讲到C语言的源 查看详情

❤️五万字《十大排序算法》动图讲解❤️(建议收藏)(代码片段)

...尔排序十、堆堆排序  今天的内容,将围绕这几张动图来展开。可以大致先简单看一下,这是一个归并排序的动图演示,我会对以上几个排序从算法原理、动图详解讲到C语言的源 查看详情

❤️[数据结构]动图详解链表(单链表/双链表……)(动图+实例)建议收藏!❤️(代码片段)

🎈作者:Linux猿🎈简介:CSDN博客专家🏆,华为云享专家🏆,C/C++、面试、刷题、算法尽管咨询我,关注我,有问题私聊!🎈关注专栏:C/C++面试通关集锦 ( 查看详情

❤️《画解数据结构》七张动图,画解单调队列❤️(建议收藏)

...深人静写算法》💜您可能感兴趣的专家文章推荐画解数据结构画解顺序表,画解链表画解栈,画解队列,画解双端队列画解哈希表,画解排序直接跳到末尾获取粉丝专属福利。零、前言  「数据结构」和「... 查看详情

❤️《画解数据结构》全网最全队列总结,九张动图搞懂队列❤️(文末有投票)(代码片段)

零、前言  「数据结构」和「算法」是密不可分的,两者往往是「相辅相成」的存在,所以,在学习「数据结构」的过程中,不免会遇到各种「算法」。  到底是先学数据结构,还是先学算法,我认为... 查看详情

❤️《画解数据结构》两万字,十张动图,画解双端队列❤️(建议收藏)(代码片段)

...解排序直接跳到末尾获取粉丝专属福利。零、前言  「数据结构」和「算法」是密不可分的,两者往往是「相辅相成」的存在,所以,在学习「数据结构」的过程中,不免会遇到各种「算法」。  到底是先学... 查看详情

❤️《画解数据结构》两万字,十张动图,画解双端队列❤️(建议收藏)(代码片段)

...解排序直接跳到末尾获取粉丝专属福利。零、前言  「数据结构」和「算法」是密不可分的,两者往往是「相辅相成」的存在,所以,在学习「数据结构」的过程中,不免会遇到各种「算法」。  到底是先学... 查看详情

❤️数据结构和算法动图演示,超详细,就怕你不会!二分查找详解建议收藏❤️(代码片段)

...关注我,有问题私聊!🎈关注专栏:图解数据结构和算法(优质好文持 查看详情

❤️万字详解「冒泡排序」,深入浅出「算法思维」❤️(代码片段)

...前言一、🎯简单释义二、🧡核心思想三、🔆动图演示四、🌳算法前置五、🥦算法描述六、🧶算法分析七、🧢优化方案八、💙代码实践九、💗代码验证零、📃前言  「冒泡排序」是最... 查看详情

二万字《算法和数据结构》三张动图,三十张彩图,c语言基础教学,之二叉搜索树详解(建议收藏)

本文已收录于专栏🌳《画解数据结构》🌳前言  我们知道,「顺序表」可以「快速索引」数据,而「链表」则可以快速的进行数据的「插入和删除」。那么,有没有一种数据结构,可以快速的实现「增... 查看详情

二万字《算法和数据结构》三张动图,三十张彩图,c语言基础教学,之二叉搜索树详解(建议收藏)

本文已收录于专栏🌳《画解数据结构》🌳前言  我们知道,「顺序表」可以「快速索引」数据,而「链表」则可以快速的进行数据的「插入和删除」。那么,有没有一种数据结构,可以快速的实现「增... 查看详情

数据结构和算法二叉树详解,动图+实例(代码片段)

...关注我,有问题私聊!🎈关注专栏:图解数据结构和算法(优质好文持 查看详情

❤️《画解数据结构》全网最清晰哈希表入门,三张动图搞懂哈希❤️(建议收藏)(代码片段)

...解链表画解栈画解队列画解二叉树画解图零、前言  「数据结构」和「算法」是密不可分的,两者往往是「相辅相成」的存在,所以,在学习「数据结构」的过程中,不免会遇到各种「算法」。  数据结构常... 查看详情

❤️动图分析top10数据库,近10年排名❤️

🎈作者:Linux猿🎈简介:CSDN博客专家🏆,华为云享专家🏆,C/C++、面试、刷题、算法尽管咨询我,关注我,有问题私聊!🎈关注专栏:Linux技术 (优质好文持续更新... 查看详情

❤️「哈希表」+「队列」将会擦出怎样的火花?❤️(代码片段)

本文已收录于专栏《画解数据结构》文章目录零、📃前言一、🎯简单释义二、🧡核心思想三、🔆动图演示四、🌳算法前置五、🥦算法描述六、🧶算法分析七、🧢优化方案八、💙源码详解九... 查看详情

❤️一看就懂!保姆级实例详解stllist容器万字整理❤️(代码片段)

🎈作者:Linux猿🎈简介:CSDN博客专家🏆,C/C++、面试、刷题、算法尽管咨询我,关注我,有问题私聊!🎈关注专栏:C/C++面试通关集锦 (优质好文持续更新中……)... 查看详情

❤️动图分析编程语言16年变化❤️

 🎈作者:Linux猿🎈简介:CSDN博客专家🏆,C/C++、面试、刷题、算法尽管咨询我,关注我,有问题私聊!🎈关注专栏:Linux技术 (优质好文持续更新中……)🚀目录... 查看详情

《画解数据结构》九张动图,画解队列(代码片段)

本文已收录于专栏🌳《画解数据结构》🌳零、前言  「数据结构」和「算法」是密不可分的,两者往往是「相辅相成」的存在,所以,在学习「数据结构」的过程中,不免会遇到各种「算法」。  到... 查看详情