当前位置: 首页 > news >正文

常见的数据结构及应用

文章目录

  • 前言
  • 数据结构介绍
    • 数组
    • 链表
    • 队列和栈
  • 总结

前言

数据结构是计算机存储、组织数据的方式。在工作中,我们通常会直接使用已经封装好的集合API,这样可以更高效地完成任务。但是作为一名程序员,掌握数据结构是非常重要的,因为它可以帮助我们更好地理解和设计算法,从而提高程序的效率和可靠性。本文将对常见的几种数据结构进行介绍,通过了解这些数据结构的特点和优势,可以更好地在不同场景下选择合适的数据结构。

数据结构介绍

常见的数据结构大体分为两种类型:线性和非线性。

线性数据结构见名思义,整体结构的图像是一条直线。包括数组、链表、栈、队列等。
非线性数据结构包括,树、堆、图等。

数组

数组是由多个元素组成的一个集合,表现形式如下图

在这里插入图片描述

在内存中存储数组的空间是连续的,每个元素占据一定的内存空间,这也是为什么在声明数组时要指定长度,不然不知道要占用多少空间。以 Java 语言为例,当声明一个数组后,数组变量会指向数组对象的起始地址,也就是第一个元素的位置,如下图

在这里插入图片描述

以此看来,当查询数组中的某个元素时,通过下标就可以计算出这个元素的内存地址,比如想查找下标为2的元素,那么arr[2]的内存地址 = arr的内存地址 + 2 * 元素大小,也就可以直接通过内存地址访问元素,时间复杂度为O(1)。

但是,数组也会带来一个问题:由于数组长度是固定的,所以在添加或删除元素时会涉及到创建新的数组来替换原数组,导致复杂度较高。例如,下面的代码演示了如何在数组末尾添加一个元素:

int[] arr = {1, 2, 3, 4, 5};  arr[arr.length] = 6; // 将要添加的元素放到数组的最后一个位置  int[] newArr = new int[arr.length + 1]; // 创建一个新的数组,长度加1  for (int i = 0; i < newArr.length; i++) {  newArr[i] = arr[i]; // 将原数组中的元素复制到新数组中  
}  arr = newArr; // 使用新数组替换原数组

示例代码在内存中的活动如下图

在这里插入图片描述

在 Java 中有很多集合的底层实现都是基于数组,例如大家常用的 ArrayList、Vector、HashMap、ArrayBlockingQueue等等。

链表

链表由一系列结点组成,每个节点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个节点地址的指针域。以 Java 为例,一个节点的结构是这样表示的:

public class Node<T> {//存储数据元素的数据域private T value;//下一个节点地址的指针域private Node next;
}

每个元素的指针指向下一个元素,从而形成链表,表现形式如下图。

在这里插入图片描述

与数组不同,链表在内存中是非连续的空间,可以充分利用计算机内存空间,实现灵活的内存动态管理,解决了数组需要预先知道数据大小的缺点。其在内存中的存储如下图

在这里插入图片描述

相比于数组,链表的插入和删除操作可以达到O(1)的复杂度(只需要将链尾的指针指向下个节点或者指向null即可),但是查找一个节点或者访问特定编号的节点则需要O(n)的时间。

上面介绍的是单向链表,单向链表有个缺点:只能只能从头到尾遍历。如果要删除倒数第二个节点,只能从头遍历。为了更加灵活的操作和更高的效率,就有了双向链表,其结构表示如下图

在这里插入图片描述

如果结构为双向链表,要删除倒数第二个节点,只用找到尾节点的前面一个节点并删除即可。Java 中的 LinkedList 就是一个双向链表的实现。

队列和栈

数组和链表的关注点主要聚焦于数据的存储结构和访问方式,而队列和栈关注的则是数据的处理顺序和逻辑,有自己的特点。

队列的特点是先进先出(FIFO):第一个进入队列的元素会第一个被访问或取出,或者说在添加元素时在队尾排队依次入队,在队头依次出队。其表现形式如下图

在这里插入图片描述

栈的特点是先进后出(FILO):第一个入栈的元素最后一个被访问或被取出,或者说最后一个入栈的元素会第一个被访问或被取出。栈只允许在栈顶进行插入和删除操作。

有一个很形象的描述就是:可以将栈想象成一个弹夹,最先装入的子弹会被压入底部,而射出时则是从顶部弹出。

在这里插入图片描述

两者的底层实现可以根据具体需求和场景选择数组或链表作为底层数据结构。例如 Java 中的 ArrayBlockingQueue 是通过数组实现的阻塞队列,LinkedBlockingQueue 通过队列实现的非阻塞队列。

树是一种非线性结构,是由n个有限节点组成一个具有层次关系的集合。树也有很多类型,比如二叉树、平衡树、2-3-4树、红黑树、B树、B+树。

二叉树是每个节点最多有两个子树的树结构,通常用于实现二叉查找树,其特点为:左子节点的值小于根节点的值,右子节点的值大于根节点的值。以 Java 为例,一个二叉查找树的结构是这样表示的:

public class Node {//当前节点的值private int value;//父节点、左子节点、右子节点private Node parent,left,right;}

表现形式如下图

在这里插入图片描述

其查询的时间复杂度为O(log n),相对于链表,查询效率大大提升。但是在最坏情况下可能会退化成O(n),比如下面这种情况

在这里插入图片描述


为了避免这种情况,诞生了AVL树。AVL树是一种自平衡的二叉查找树,在进行插入和删除操作时,会通过左旋或者右旋自动调整自身的结构,确保每个节点的左右子树的高度差不超过1,从而保持树的平衡,也保障了查询的时间复杂度为O(log n)。

以下图为例,当插入节点5时,节点7左右子树的高度差为2,这时候节点7就需要进行右旋保持树的平衡。

在这里插入图片描述
右旋就是:以某个节点为旋转点,其左子节点变为其父节点,左子节点的右子节点变为其左子节点,右子节点不变。
同理,左旋就是:以某个节点为旋转点,其右子节点变为其父节点,右子节点的左子节点变为其右子节点,左子节点不变。


虽然AVL通过旋转保持树的平衡,但是在插入和删除频繁的场景中,频繁的旋转会导致性能下降,为解决此问题红黑树被提出。

红黑树大家应该都比较耳熟,面试的时候应该经常会被问到,但是理不理解是另一回事。

红黑树也是自平衡的二叉查找树,它是通过节点颜色来保证树的平衡的。相对AVL,红黑树较难被理解,第一疑惑就是:“不也是左旋右旋吗?还这么麻烦,节点颜色变来变去,迷惑谁呢?”。

红黑树后面专门写一篇文章介绍,这里先给结论:红黑树的旋转次数相对于AVL树来说较少,因此在插入、删除等操作较多的情况下,通常使用红黑树,比如大家都知道的HashMap。下图显示的是按顺序插入9, 7, 6, 10, 5, 8, 4, 2, 1, 0的AVL树和红黑树,可以看到两者在结构上存在一定的差异。

在这里插入图片描述


上面说的几种树都是二叉树,即每个节点只有两个分支,并且都都是有序的。因为只有两个分支,所以这也是二叉树的通病,当数据越来越多的时候,树的高度也会越高,这种情况就不适合数据库和文件系统这种场景了。

上面提到的几种树结构都是二叉树,每个节点只有两个子节点,并且都是有序的。当数据量不断增加时,二叉树的高度也会逐渐增加,从而导致查询效率降低,并且在有磁盘I/O操作的场景下,树越高越不利于查询。

为了解决上述问题,采用多叉树结构,可以有效地降低树的高度,提高查询效率。

常见的多叉树有2-3-4树、B树和B+树,通常在数据库和文件系统中会使用到,其表现形式如下图。

在这里插入图片描述

B+树是B树的一种扩展,它更适合用于磁盘或其他存储设备中。在B+树中,非叶子节点不保存数据信息,只保存关键字和子节点指针,这样会存储更多有效数据,比如索引。同时,每个叶子节点都指向相邻叶子节点的指针,这样的话在数据库范围查询会变得非常高效。

堆是一种特殊的树形数据结构,其特点为:每个节点都大于或等于(小于或等于)其每个子节点。

常见的堆有二叉堆、斐波那契堆等,二叉堆是一种完全二叉树,可以分为最大堆和最小堆,最大堆中的每个节点都大于或等于其子节点,最小堆中的每个节点都小于或等于其子节点。下图左为最大堆的表示,右不符合为一个完全二叉树(依次从左到右插入的节点为完全二叉树)。

在这里插入图片描述

堆通常被用作优先队列,因为堆的根节点总是最大的或最小的。

总结

很多编程语言都提供了不同类型的集合类,以 Java 为例,我们常用的集合有List、Set、Queue、Map,其底层的实现就是数组、链表或树这几种数据结构。所以通过了解数据结构,我们可以更好地选择和使用这些集合,甚至可以自行设计更高效的数据结构来解决问题。

相关文章:

常见的数据结构及应用

文章目录 前言数据结构介绍数组链表队列和栈树堆 总结 前言 数据结构是计算机存储、组织数据的方式。在工作中&#xff0c;我们通常会直接使用已经封装好的集合API&#xff0c;这样可以更高效地完成任务。但是作为一名程序员&#xff0c;掌握数据结构是非常重要的&#xff0c;…...

基于模型预测人工势场的船舶运动规划方法,考虑复杂遭遇场景下的COLREG(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

【UE5 Cesium】19-Cesium for Unreal 建立飞行跟踪器(4)

遗留问题 在上一篇博客中&#xff08;【UE5 Cesium】18-Cesium for Unreal 建立飞行跟踪器&#xff08;3&#xff09;&#xff09;&#xff0c;我们实现了飞机变速飞行的功能&#xff0c;但是还存在两个问题&#xff0c;分别是&#xff1a; &#xff08;1&#xff09;由于UE的…...

TrustZone

TrustZone技术 让我们从最重要的问题开始&#xff1a;为什么存在TrustZone技术&#xff0c;它防御什么&#xff1f;保护用 C 和 C 编写的大型程序免受黑客攻击可能是一个挑战。内存损坏漏洞是一个常见问题&#xff0c;尽管消除它们是安全工程师的核心目标&#xff0c;但从操作…...

✔ ★【备战实习(面经+项目+算法)】 10.16学习时间表(总计学习时间:5h)

✔ ★【备战实习&#xff08;面经项目算法&#xff09;】 坚持完成每天必做如何找到好工作1. 科学的学习方法&#xff08;专注&#xff01;效率&#xff01;记忆&#xff01;心流&#xff01;&#xff09;2. 每天认真完成必做项&#xff0c;踏实学习技术 认真完成每天必做&…...

React + Router

React Router 这个只是专门讲解 React Router 新开的例子。 教程来源&#xff1a;https://reactrouter.com/en/main/start/tutorial 创建新项目 yarn create vite my-react-router-app --template react-ts cd my-react-router-app yarn安装 React Router 依赖: yarn add…...

微信小程序设置动态变量设值

微信小程序设置动态变量设值 微信小程序如何动态变量设值&#xff1f; 示例代码如下&#xff1a; setValFunc() {const key this.data.currentPickerid; // 业务需求动态键值key&#xff0c;或者是上一界面获取的动态key值const value 变量值;this.setData({[${key}]: valu…...

闪站侠洗衣洗鞋多门店多用户管理系统,洗鞋店干洗店小程序开发;

闪站侠洗护软件是多分店多用户管理系统&#xff0c;一个分店可以同时关联多个用户。闪站侠洗护管理软件通过互联网为洗衣店/洗鞋店干洗店提供加盟或直营连锁管理&#xff1b; 实现会员洗衣的门店收衣->上门收衣->开单拍照->清洗护理/工厂洗涤->微&#xff5c;信/短…...

JDBC增删改查示例

数据库表 CREATE TABLE customers ( id int NOT NULL AUTO_INCREMENT, name varchar(15) DEFAULT NULL, email varchar(20) DEFAULT NULL, birth date DEFAULT NULL, photo mediumblob, PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT39 DEFAULT CHARSETgb2312;…...

emqx broker安装

emqx broker安装 Emq x百万级开源 MQTT 消息服务器 是基于 Erlang/OTP 语言平台开发 一款完全开源&#xff0c;高可用低时延的百万级分布式物联网 MQTT 5.0 消息服务器 官方地址: https://www.emqx.com/zh Centos7 安装 #下载Centos7 amd64位版本 wget https://www.emqx.c…...

如何选择国产压力测试工具?

随着互联网的飞速发展&#xff0c;软件应用的性能和稳定性变得愈发重要。无论是在线购物网站、社交媒体平台还是移动应用程序&#xff0c;用户都期望能够快速、流畅地访问和使用它们。为了确保应用程序在高负载下仍能够正常运行&#xff0c;压力测试工具变得至关重要。在国内&a…...

基于AT89C51流水花样灯proteus仿真设计

一、仿真原理图&#xff1a; 二、仿真效果图&#xff1a; 三、仿真工程&#xff1a; c51单片机流水灯花样灯proteus仿真设计资源-CSDN文库...

android U广播详解(二)

android U广播详解&#xff08;一&#xff09; 基础代码介绍 广播相关 // 用作单个进程批量分发receivers&#xff0c;已被丢弃 frameworks/base/services/core/java/com/android/server/am/BroadcastReceiverBatch.java // 主要逻辑所在类&#xff0c;包括入队、分发、结束…...

导航守卫的使用记录和beforeEach( )死循环的问题

前置导航守卫beforeEach的使用 import Vue from vue import VueRouter from vue-router // 进度条 import NProgress from nprogress import nprogress/nprogress.cssVue.use(VueRouter)// 路由表 const routes [{path: "/",redirect: "/home",},{path: …...

SpringMVC源码分析(三)HandlerExceptionResolver启动和异常处理源码分析

问题&#xff1a;异常处理器在SpringMVC中是如何进行初始化以及使用的&#xff1f; Spring MVC提供处理异常的方式主要分为两种&#xff1a; 1、实现HandlerExceptionResolver方式&#xff08;HandlerExceptionResolver是一个接口&#xff0c;在SpringMVC有一些默认的实现也可以…...

系统架构与Tomcat的安装和配置

2023.10.16 今天是学习javaweb的第一天&#xff0c;主要学习了系统架构的相关知识和原理&#xff0c;下载了web服务器软件&#xff1a;Tomcat&#xff0c;并对其进行了配置。 系统架构 包括&#xff1a;C/S架构 和 B/S架构。 C/S架构&#xff1a; Client / Server&#xff0…...

【Shell脚本】根据起止日期获取Alert日志内容

【Shell脚本】根据起止日期获取Alert日志内容 根据输入的起止日期字符串&#xff0c;检索Oracle告警日志&#xff0c;打印中间的日志行内容。 #!/bin/bash # $1 START_TIME_STR, e.g. "Oct 17 07:" # $2 END_TIME_STR, e.g. "Oct 17 08:" source /home/o…...

Library projects cannot set applicationId. applicationId is set to

Library projects cannot set applicationId. applicationId is set to com.xxx.library_cache in default config. 删掉即可...

【兔子王赠书第2期】《案例学Python(基础篇)》

文章目录 前言推荐图书本书特色本书目录本书样章本书读者对象粉丝福利丨评论免费赠书尾声 前言 随着人工智能和大数据的蓬勃发展&#xff0c;Python将会得到越来越多开发者的喜爱和应用。身边有很多朋友都开始使用Python语言进行开发。正是因为Python是一门如此受欢迎的编程语…...

用户行为数据案例

一、环境要求 HadoopHiveSparkHBase 开发环境。 二、数据描述 本数据集包含了2017-09-11至2017-12-03之间有行为的约5458位随机用户的所有行为&#xff08;行为包括点击、购买、加购、喜欢&#xff09;。数据集的每一行表示一条用户行为&#xff0c;由用户ID、商品ID、商品类…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

【算法训练营Day07】字符串part1

文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接&#xff1a;344. 反转字符串 双指针法&#xff0c;两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲

文章目录 前言第一部分&#xff1a;体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分&#xff1a;体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

【Veristand】Veristand环境安装教程-Linux RT / Windows

首先声明&#xff0c;此教程是针对Simulink编译模型并导入Veristand中编写的&#xff0c;同时需要注意的是老用户编译可能用的是Veristand Model Framework&#xff0c;那个是历史版本&#xff0c;且NI不会再维护&#xff0c;新版本编译支持为VeriStand Model Generation Suppo…...

边缘计算网关提升水产养殖尾水处理的远程运维效率

一、项目背景 随着水产养殖行业的快速发展&#xff0c;养殖尾水的处理成为了一个亟待解决的环保问题。传统的尾水处理方式不仅效率低下&#xff0c;而且难以实现精准监控和管理。为了提升尾水处理的效果和效率&#xff0c;同时降低人力成本&#xff0c;某大型水产养殖企业决定…...

基于谷歌ADK的 智能产品推荐系统(2): 模块功能详解

在我的上一篇博客&#xff1a;基于谷歌ADK的 智能产品推荐系统(1): 功能简介-CSDN博客 中我们介绍了个性化购物 Agent 项目&#xff0c;该项目展示了一个强大的框架&#xff0c;旨在模拟和实现在线购物环境中的智能导购。它不仅仅是一个简单的聊天机器人&#xff0c;更是一个集…...

【Zephyr 系列 16】构建 BLE + LoRa 协同通信系统:网关转发与混合调度实战

🧠关键词:Zephyr、BLE、LoRa、混合通信、事件驱动、网关中继、低功耗调度 📌面向读者:希望将 BLE 和 LoRa 结合应用于资产追踪、环境监测、远程数据采集等场景的开发者 📊篇幅预计:5300+ 字 🧭 背景与需求 在许多 IoT 项目中,单一通信方式往往难以兼顾近场数据采集…...