【数据结构】线性结构——数组、链表、栈和队列

news2024/9/21 0:33:20

目录

前言

一、数组(Array)

1.1优点

1.2缺点

1.3适用场景

二、链表(Linked List)

2.1优点

2.2缺点

2.3适用场景

三、栈(Stack)

3.1优点

3.2缺点

3.3适用场景

四、队列(Queue)

4.1优点

4.2缺点

4.3适用场景


🌈嗨!我是Filotimo__🌈。很高兴与大家相识,希望我的博客能对你有所帮助。

💡本文由Filotimo__✍️原创,首发于CSDN📚。

📣如需转载,请事先与我联系以获得授权⚠️。

🎁欢迎大家给我点赞👍、收藏⭐️,并在留言区📝与我互动,这些都是我前进的动力!

🌟我的格言:森林草木都有自己认为对的角度🌟。

前言

数据结构指的是计算机科学中用来组织和存储数据的方式,涉及数据元素之间的关系及其操作定义。数据结构可以分为线性结构和非线性结构。其中,线性结构是指数据元素之间存在一对一的关系,包括数组、链表、栈和队列等。


一、数组(Array)

数组是一种在内存中连续存储多个相同类型元素的数据结构。数组通过索引(通常从0开始)来访问每个元素。

示例代码(以下所有代码都是用C语言编写的)

#include <stdio.h>

#define SIZE 5

int main() {
    // 创建一个整数数组
    int arr[SIZE] = {1, 2, 3, 4, 5};

    // 访问数组元素
    printf("Element at index 0: %d\n", arr[0]);  // 输出: 1
    printf("Element at index 2: %d\n", arr[2]);  // 输出: 3

    // 修改数组元素
    arr[1] = 10;
    printf("Updated array: ");
    for (int i = 0; i < SIZE; ++i) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}

运行截图

1.1优点

①        快速访问:由于元素在内存中连续存储,可以通过索引直接访问任何元素,时间复杂度为 O(1)。

②        简单:实现简单直观,是最基础的数据结构之一。

1.2缺点

①        固定大小:数组创建时大小固定,通常无法动态扩展,需要预先确定容量。

②        插入和删除操作慢:在数组中间或开头插入或删除元素需要移动其他元素,时间复杂度为 O(n)。

1.3适用场景

数组适合于元素类型固定、需要频繁访问元素且不需要经常插入或删除元素的场景。

二、链表(Linked List)

链表是一种非连续、非顺序的数据结构,由节点组成,每个节点包含数据和指向下一个节点的指针(或引用)。根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。

示例代码

#include <stdio.h>
#include <stdlib.h>

// 定义链表节点结构
typedef struct Node {
    int data;
    struct Node* next;
} Node;

// 创建一个新的节点
Node* create_node(int data) {
    Node* new_node = (Node*)malloc(sizeof(Node));  // 分配内存
    new_node->data = data;
    new_node->next = NULL;
    return new_node;
}

// 向链表末尾添加节点
void append(Node** head_ref, int new_data) {
    Node* new_node = create_node(new_data);
    Node* last = *head_ref;
    if (*head_ref == NULL) {
        *head_ref = new_node;
        return;
    }
    while (last->next != NULL) {
        last = last->next;
    }
    last->next = new_node;
}

// 打印链表
void print_list(Node* node) {
    while (node != NULL) {
        printf("%d -> ", node->data);
        node = node->next;
    }
    printf("NULL\n");
}

// 释放链表内存
void free_list(Node* node) {
    Node* temp;
    while (node != NULL) {
        temp = node;
        node = node->next;
        free(temp);
    }
}

int main() {
    Node* head = NULL;
    
    // 创建链表
    append(&head, 1);
    append(&head, 2);
    append(&head, 3);
    append(&head, 4);
    
    // 打印链表
    printf("Linked List: ");
    print_list(head);
    
    // 释放链表
    free_list(head);
    
    return 0;
}

运行截图

2.1优点

①        动态大小:链表可以动态地分配内存空间,不像数组需要预先分配固定大小的空间。

②        插入和删除快速:在链表中插入和删除元素不需要移动其他元素,只需要改变指针指向,时间复杂度为 O(1)。

2.2缺点

①        随机访问慢:链表的元素不连续存储,访问特定位置的元素需要从头开始遍历,时间复杂度为 O(n)。

②        额外空间:每个节点除了存储数据外,还需存储指针,占用较多的内存空间。

2.3适用场景

链表适合于需要频繁插入和删除操作、内存空间不确定或者不需要随机访问元素的场景。

三、栈(Stack)

栈是一种特殊的线性表,具有后进先出(LIFO,Last In First Out)的特点,只允许在一端进行插入和删除操作。这一端被称为栈顶,另一端称为栈底。

示例代码

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 100  // 栈的最大容量

// 定义栈结构体
typedef struct {
    int items[MAX_SIZE];
    int top;  // 栈顶指针
} Stack;

// 初始化栈
void init(Stack* stack) {
    stack->top = -1;  // 栈顶指针初始化为-1,表示栈为空
}

// 判断栈是否为空
int is_empty(Stack* stack) {
    return stack->top == -1;
}

// 判断栈是否已满
int is_full(Stack* stack) {
    return stack->top == MAX_SIZE - 1;
}

// 入栈操作
void push(Stack* stack, int item) {
    if (is_full(stack)) {
        printf("Stack overflow\n");
        return;
    }
    stack->items[++stack->top] = item;  // 栈顶指针先加一,然后添加元素
}

// 出栈操作
int pop(Stack* stack) {
    if (is_empty(stack)) {
        printf("Stack underflow\n");
        return -1;  // 返回-1表示出栈失败
    }
    return stack->items[stack->top--];  // 返回栈顶元素,并将栈顶指针减一
}

// 查看栈顶元素
int peek(Stack* stack) {
    if (is_empty(stack)) {
        printf("Stack is empty\n");
        return -1;  // 返回-1表示栈为空
    }
    return stack->items[stack->top];  // 仅返回栈顶元素,不改变栈的状态
}

// 获取栈的大小
int size(Stack* stack) {
    return stack->top + 1;
}

int main() {
    Stack stack;
    init(&stack);  // 初始化栈
    
    push(&stack, 10);
    push(&stack, 20);
    push(&stack, 30);

    printf("Top element is %d\n", peek(&stack));  // 输出: 30
    printf("Stack size is %d\n", size(&stack));   // 输出: 3

    printf("Popped element is %d\n", pop(&stack));  // 输出: 30
    printf("Popped element is %d\n", pop(&stack));  // 输出: 20

    printf("Top element is %d\n", peek(&stack));  // 输出: 10

    return 0;
}

运行截图

3.1优点

①        操作简单:只允许在栈顶进行插入和删除操作,实现简单直观。

②        内存管理方便:栈的内存管理由系统自动处理,无需程序员手动管理。


3.2缺点

①        容量限制:栈的大小受限于系统内存的大小,可能会造成栈溢出。

②        不支持随机访问:由于只能操作栈顶元素,无法直接访问栈中间的元素。


3.3适用场景

①        递归算法(如深度优先搜索)

②        表达式求值(如逆波兰表达式)

③        括号匹配(如编译器的语法分析)

④        历史记录(如浏览器前进后退功能)

⑤        撤销操作(如文本编辑器的撤销功能)

四、队列(Queue)

队列是一种具有先进先出(FIFO,First In First Out)特性的数据结构,允许在一端插入(enqueue)元素,另一端删除(dequeue)元素。通常用于需要按顺序处理数据的场景。

示例代码

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 100  // 队列的最大容量

// 定义队列结构体
typedef struct {
    int items[MAX_SIZE];
    int front;  // 队头指针
    int rear;   // 队尾指针
    int size;   // 队列当前元素个数
} Queue;

// 初始化队列
void init(Queue* queue) {
    queue->front = 0;
    queue->rear = -1;
    queue->size = 0;
}

// 判断队列是否为空
int is_empty(Queue* queue) {
    return queue->size == 0;
}

// 判断队列是否已满
int is_full(Queue* queue) {
    return queue->size == MAX_SIZE;
}

// 入队操作
void enqueue(Queue* queue, int item) {
    if (is_full(queue)) {
        printf("Queue overflow\n");
        return;
    }
    queue->rear = (queue->rear + 1) % MAX_SIZE;  // 环形队列实现
    queue->items[queue->rear] = item;
    queue->size++;
}

// 出队操作
int dequeue(Queue* queue) {
    if (is_empty(queue)) {
        printf("Queue underflow\n");
        return -1;  // 返回-1表示出队失败
    }
    int dequeued_item = queue->items[queue->front];
    queue->front = (queue->front + 1) % MAX_SIZE;  // 环形队列实现
    queue->size--;
    return dequeued_item;
}

// 查看队头元素
int peek(Queue* queue) {
    if (is_empty(queue)) {
        printf("Queue is empty\n");
        return -1;  // 返回-1表示队列为空
    }
    return queue->items[queue->front];
}

// 获取队列的大小
int size(Queue* queue) {
    return queue->size;
}

int main() {
    Queue queue;
    init(&queue);  // 初始化队列
    
    enqueue(&queue, 10);
    enqueue(&queue, 20);
    enqueue(&queue, 30);

    printf("Front element is %d\n", peek(&queue));  // 输出: 10
    printf("Queue size is %d\n", size(&queue));     // 输出: 3

    printf("Dequeued element is %d\n", dequeue(&queue));  // 输出: 10
    printf("Dequeued element is %d\n", dequeue(&queue));  // 输出: 20

    printf("Front element is %d\n", peek(&queue));  // 输出: 30

    return 0;
}

运行截图

4.1优点

①        按序处理:队列确保元素按照入队的顺序处理,符合先进先出的逻辑。

②        操作简单:队列仅支持在队尾插入和队头删除操作,设计和实现都较为简单。

③        资源管理:队列的大小可以动态增长,灵活适应不同数据量的需求。

4.2缺点

①        固定容量:队列的大小通常是固定的,可能会导致队列满时无法继续入队(队列溢出)。

②        不支持随机访问:只能访问队头元素,不能直接访问队列中间的元素。

4.3适用场景

①        任务调度:用于任务按顺序执行,例如操作系统中的进程调度。

②        消息传递:用于实现异步消息传递机制,例如消息队列中间件。

③        广度优先搜索:在图的遍历中,广度优先搜索算法需要使用队列来管理遍历的节点顺序。

④        缓冲:用于平衡生产者和消费者之间的速度差异,例如生产者消费者模型中的缓冲区。

⑤        网络数据包处理:在网络数据传输中,使用队列来管理接收到的数据包。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1935922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【python】Python高阶函数--reduce函数的高阶用法解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Redis常用的5大数据类型

Reids字符串&#xff08;String&#xff09; 设置相同的key&#xff0c;之前内容会覆盖掉 Redis列表&#xff08;List&#xff09; 常用命令 从左往右放值 数据结构 Redis集合&#xff08;set&#xff09; sadd<key><value1><value2>...... 数据结构 Set数据…

前端组件化开发:以Vue自定义底部操作栏组件为例

摘要 随着前端技术的不断演进&#xff0c;组件化开发逐渐成为提升前端开发效率和代码可维护性的关键手段。本文将通过介绍一款Vue自定义的底部操作栏组件&#xff0c;探讨前端组件化开发的重要性、实践过程及其带来的优势。 一、引言 随着Web应用的日益复杂&#xff0c;传统的…

「豆包Marscode体验官」 | 云端 IDE 启动 Rust 体验

theme: cyanosis 我正在参加「豆包MarsCode初体验」征文活动 MarsCode 可以看作一个运行在服务端的远程 VSCode开发环境。 对于我这种想要学习体验某些语言&#xff0c;但不想在电脑里装环境的人来说非常友好。本文就来介绍一下在 MarsCode里&#xff0c;我的体验 rust 开发体验…

Games101学习笔记 Lecture22 Animation(cont.)

Lecture22 Animation(cont. 一、单个粒子模拟Ordinary Differential Equation ODE 常微分方程ODE求解方法——欧拉方法解决不稳定中点法改进欧拉方法自适应步长隐式欧拉方法 二、流体模拟基于位置的方法物质点方法 一、单个粒子模拟 想模拟粒子在场中的运动 Ordinary Differe…

Token Labeling(NeurIPS 2021, ByteDance)论文解读

paper&#xff1a;All Tokens Matter: Token Labeling for Training Better Vision Transformers official implementation&#xff1a;https://github.com/zihangJiang/TokenLabeling 出发点 ViTs的局限性&#xff1a;尽管ViTs在捕捉长距离依赖方面表现出色&#xff0c; 但…

代码随想录算法训练营第五十八天|108.冗余连接、109.冗余连接II

108.冗余连接 题目链接&#xff1a;108.冗余连接 文档讲解&#xff1a;代码随想录 状态&#xff1a;还行 思路&#xff1a; 并查集可以解决什么问题&#xff1a;两个节点是否在一个集合&#xff0c;也可以将两个节点添加到一个集合中。 题解&#xff1a; public class Main {p…

套用BI方案做数据可视化是种什么体验?

在数字化转型的浪潮中&#xff0c;数据可视化作为连接数据与决策的桥梁&#xff0c;其重要性日益凸显。近期&#xff0c;我有幸体验了奥威BI方案进行数据可视化的全过程&#xff0c;这不仅是一次技术上的探索&#xff0c;更是一次对高效、智能数据分析的深刻感受。 初识奥威&a…

.net dataexcel 脚本公式 函数源码

示例如: ScriptExec(""sum(1, 2, 3, 4)"") 结果等于10 using Feng.Excel.Builder; using Feng.Excel.Collections; using Feng.Excel.Interfaces; using Feng.Script.CBEexpress; using Feng.Script.Method; using System; using System.Collections.Gen…

场景分析法挖掘需求的常见4大步骤

场景分析方法&#xff0c;有助于精确定位需求&#xff0c;优化产品设计&#xff0c;促进团队协同&#xff0c;减少项目风险&#xff0c;提升用户满意度与市场竞争力。若场景分析不足&#xff0c;产品可能偏离用户需求&#xff0c;导致功能冗余或缺失&#xff0c;用户体验差&…

java中传引用问题

在 Java 中&#xff0c;所有对象都是通过引用传递的&#xff0c;而基本数据类型是通过值传递的。 引用传递&#xff1a; 当一个对象作为参数传递给方法时&#xff0c;传递的是对象的引用。对这个对象引用进行的修改会影响到原始对象。例如&#xff1a; public class Test {p…

Designing Data-Intensive Applications数据密集型应用系统设计-读书笔记

目录 第一部分可靠性、可扩展性、可维护性硬件故障描述负载 吞吐与延迟可维护性 第二章 数据模型与查询语言第三章索引哈希索引B-tree事务 第三章 编码第二部分、分布式数据系统第五章 数据复制单主从复制节点失效日志实现复制滞后问题 多主节点复制 第六章、数据分区3 第一部分…

10个常见的电缆载流表,值得收藏!

众所周知,电线电缆的载流是所有电工、电气人员都必须具备的基本储备,但是如果要将那么多的“数字”都记得清清楚楚,还是有一点困难的!今天咱们就做了一个电力电缆载流量对照表,速度收藏!下次参考不迷路! 1、0.6/1KV聚氯乙烯绝缘电力电缆载流量 以上电缆载流量计算条件:…

世界启动Ⅳ--利用AI和费曼技巧学习一切

前言 有无数的学习技巧可以帮助你消化复杂的概念&#xff0c;并有信心记住它们。如果你像我一样是一个不断学习的学生&#xff0c;你就会明白有效学习方法的重要性。其中最简单的一种就是费曼技巧。 在本文中&#xff0c;我将解释如何有效地应用费曼学习方法&#xff0c;以及…

应用最优化方法及MATLAB实现——第5章代码实现

一、概述 继上一章代码后&#xff0c;这篇主要是针对于第5章代码的实现。部分代码有更改&#xff0c;会在下面说明&#xff0c;程序运行结果跟书中不完全一样&#xff0c;因为部分参数&#xff0c;书中并没有给出其在运行时设置的值&#xff0c;所以我根据我自己的调试进行了设…

迁移学习在乳腺浸润性导管癌病理图像分类中的应用

1. 引言 乳腺癌主要有两种类型:原位癌:原位癌是非常早期的癌症&#xff0c;开始在乳管中扩散&#xff0c;但没有扩散到乳房组织的其他部分。这也称为导管原位癌(DCIS)。浸润性乳腺癌:浸润性乳腺癌已经扩散(侵入)到周围的乳腺组织。侵袭性癌症比原位癌更难治愈。将乳汁输送到乳…

C++中的new和模版

前言 随着C的学习&#xff0c;讲了C的发展过程、流插入、流提取、函数缺省值、类与构造等等。接下来学习C很方便的 玩意&#xff0c;函数模版。函数模版就像是模具一样&#xff0c;C会自动用模版编译出合适的函数供程序员使用。以前不同类型相同操作的函数都能通过函数模版&…

【iOS】——内存对齐

内存对齐是什么 内存对齐指的是数据在内存中的布局方式&#xff0c;它确保每个数据类型的起始地址能够满足该类型对齐的要求。这是因为现代处理器在访问内存时&#xff0c;如果数据的起始地址能够对齐到一定的边界&#xff0c;那么访问速度会更快。这种对齐通常是基于数据类型…

客户中心应急管理的作用和特征

近些年作为事故、灾难等风险的预防主体和第一响应者&#xff0c;客户中心的应急管理取得了较大进展&#xff0c;但总体上仍存在很多薄弱环节&#xff0c;如安全事故频发&#xff0c;自然灾害、公共卫生、社会安全事件等给运营机构带来了多方面的不利影响。从信息角度看&#xf…

20240720 每日AI必读资讯

OpenAI 推出GPT-4o mini取代 GPT 3.5&#xff01; - 性能超越 GPT 4&#xff0c;而且更快更便宜 - 该模型在MMLU上得分为82%&#xff0c;在LMSYS排行榜上的聊天偏好测试中表现优于GPT-4。 - GPT-4o mini的定价为每百万输入标记15美分和每百万输出标记60美分&#xff0c;比之…