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

重生之数据结构与算法----数组链表

简介

数据结构的本质,只有两种结构,数组与链表。其它的都是它的衍生与组合算法的本质就是穷举

数组

数组可以分为两大类,静态数组动态数组。静态数组的本质是一段连续的内存,因为是连续的,所以我们可以采用偏移量的方式来对元素实现快速访问。而动态数组则是对静态数组的封装,使得更加方便操作元素。有了动态数组,后续的栈,哈希,队列都能更加优雅的实现。

静态数组

  1. 数组的超能力随机访问。只要任意一个索引,都能推测出元素的内存地址,而计算机的内存寻址能力为Log(1),所以数组的随机访问时间复杂度也同样为Log(1)

  2. 数组的局限性由于数组的大小是固定的,所以当数组满了,或者需要在中间插入/删除时。都需要移动元素,这时候时间复杂度就上升为Log(N)

动态数组

动态数组无法解决静态数组Log(N)的问题,它只是帮你隐藏了动态扩容与元素搬移的过程,以及更加易用的API。

数组随机访问的超能力源于数组连续的内存空间,而连续的内存空间就不可避免地面对元素搬移和扩缩容的问题

一个简单的动态数组

public class MyList<T>(){//真正存储数据的底层private T[] arr = new T[5];//记录元素的数量public int Count { get; private set; }/// <summary>/// 增/// </summary>/// <param name="item"></param>public void Add(T item){if (Count == arr.Length){//扩容Resize(Count * 2);}arr[Count] = item;Count++;}/// <summary>/// 删/// </summary>/// <param name="idx"></param>public void RemoveAt(int idx){if (Count == arr.Length / 4){//缩容Resize(arr.Length / 2);}Count--;for (int i = idx; i < Count; i++){arr[i] = arr[i + 1];}arr[Count] = default(T);}public void Remove(T item){var idx = FindIndex(item);RemoveAt(idx);}/// <summary>/// 改/// </summary>/// <param name="idx"></param>/// <param name="newItem"></param>public void Put(int idx,T newItem){arr[idx] = newItem;}/// <summary>/// 查/// </summary>/// <param name="item"></param>/// <returns></returns>public int FindIndex(T item){for(int i = 0; i < arr.Length; i++){if (item.Equals(arr[i]))return i;}return -1;}/// <summary>/// 扩容/缩容操作/// </summary>/// <param name="initCapacity"></param>private void Resize(int initCapacity){var newArray=new T[initCapacity];for(var i = 0; i < Count; i++){newArray[i] = arr[i];}arr = newArray;}}

数组的变种:环形数组

有人可能会问了?数组不是一段连续的内存吗?怎么可能是环形的?从物理角度出发,这确实不可能。但从逻辑角度出发,这是有可能的。其核心内容就是利用求模运算

        public static void Run(){var arr = new int[] { 1, 2, 3, 4, 5, 6 };var i = 0;while (arr.Length > 0){Console.WriteLine(arr[i]);//关键代码在此,当i遍历到末尾时,i+1与arr.Length去余数变成0//从逻辑上完成了闭环i = (i + 1) % arr.Length;if ((i % arr.Length) == 0){Console.WriteLine("完成了一次循环,i归零");Thread.Sleep(1000);}}}

环形数组的关键在于,它维护了两个指针 start 和 end,start 指向第一个有效元素的索引,end 指向最后一个有效元素的下一个位置索引环形数组解决了什么问题?数组在头部增删从O(N),优化为O(1)

链表

链表分为单链表双链表,单链表只有一个指针,指向next元素。双链表有两个指针,分别指向previous与next。除此之外并无其它区别。主要功能区别在于能否向前遍历。

为什么需要链表

前面说到,数组的本质是一段连续的内存,当元素移动/扩容时,需要one by one 移动,花销很大。那有没有一种能突破内存限制的数据结构呢?链表就应运而生。链表不需要连续内存,它们可以分配在天南海北,它们之间的联系靠next/prev链接,将零散的元素串成一个链式结构。

这么做有两个好处

  1. 提高内存利用率,分配在哪都可以。所以可以降低内存碎片

  2. 方便扩容与移动,只需要重新指向next/previous 即可实现增,删,改等操作,无需移动元素与扩容。

但万物皆有代价,因为链表的不连续性,所以无法利用快速随机访问来定位元素,只能一个一个的遍历来确定元素。因此链表的查询复杂度为Log(N)

一个简单的链表

public class MyLinkedList<T>
{public static void Run(){var linked = new MyLinkedList<string>();linked.AddLast("a");linked.AddLast("b");linked.AddLast("c");linked.AddLast("d");linked.Add(1, "bc");linked.Put(1, "aaaa");Console.WriteLine(linked.ToString()) ;}/// <summary>/// 虚拟头尾节点,有两个好处/// 1.无论链表是否为空, 两个虚拟节点都存在,避免很多边界值处理的情况。/// 2.如果要在尾部插入数据,如果不知道尾节点,那么需要复杂度退化成O(N),因为要从头开始遍历到尾部。/// </summary>private Node _head, _tail; public int Count { get; private set; }public MyLinkedList(){_tail = new Node();_head = new Node();_head.Next = _tail;_tail.Prev = _head;}public void AddLast(T item){var prev = _tail.Prev;var next = _tail;var node = new Node(item);node.Next = next;node.Prev = prev;prev.Next = node;next.Prev = node;Count++;}public void AddFirst(T item){var prev = _head;var next = _head.Next;var node=new Node(item);node.Prev= prev;node.Next= next;prev.Next= node;next.Prev = node;Count++;}public void Add(int idx,T item){var t = Get(idx);var next = t.Next;var prev = t;var node = new Node(item);node.Next = next;node.Prev = prev;prev.Next = node;next.Prev = node;}public void Remove(int idx){var t = Get(idx);var prev = t.Prev;var next = t.Next;prev.Next = next;next.Prev = next;t = null;Count--;}public void Put(int idx,T item){var t = Get(idx);t.Value= item;}private Node? Get(int idx){var node = _head.Next;//这里有个优化空间,可以通过idx在Count的哪个区间。从而决定从head还是从tail开始遍历for (int i = 0; i < idx; i++){node = node.Next;}return node;}public override string ToString(){var sb = new StringBuilder();var node = _head.Next;while (node != null && node.Value != null){sb.Append($"{node.Value}<->");node = node.Next;}sb.Append("null");return sb.ToString();}private class Node{public T? Value { get; set; }public Node Next { get; set; }public Node Prev { get; set; }public Node(){Value=default(T);}public Node(T value){Value = value;}}
}

链表的变种:跳表

在上面简单的例子中,查询的复杂度为O(N),插入的复杂度为O(1).主要消耗在查询操作,只能从头结点开始,逐个遍历到目标节点。所以我们优化的重点就在于优化查询。

上面的例子中,我们使用了虚拟头尾节点来空间换时间,提高插入效率。同样的,我们也可以采用这个思路来提高查询效率

跳表核心原理

index  0  1  2  3  4  5  6  7  8  9
node   a->b->c->d->e->f->g->h->i->j

此时此刻,你想拿到h的节点,你需要从0开始遍历直到7。这时候你就想,如果我能提前知道6的位置就好了,这样我就只需要Next就能快速得到h

调表就是如此

indexLevel   0-----------------------8-----10
indexLevel   0-----------4-----------8-----10
indexLevel   0-----2-----4-----6-----8-----10
indexLevel   0--1--2--3--4--5--6--7--8--9--10
nodeLevel    a->b->c->d->e->f->g->h->i->j->k

调表在原链表的基础上,增加了多层索引,每向上一层,索引减少一半,所以索引的高度是O(log N)

  1. 首先从最高层索引开始往下搜,索引7在[0,8]区间

  2. 从节点0开始,发现7在【4,8】,拿到节点4的地址

  3. 从节点4开始,发现7在【6,8】,拿到节点6的地址

  4. 从节点6开始,发现7在【6,7】,最终找到节点7

在搜索的过程中,会经过O(log N)层索引,所以时间复杂度为O(log N)

调表实现比较复杂,当新增与删除时,还需考虑索引的动态调整,需要保证尽可能的二分,否则时间复杂度又会退化为O(N)有点类似自平衡的二叉搜索数,不过相对来说比较简单。

文章转载自:叫我安不理

原文链接:重生之数据结构与算法----数组&链表 - 叫我安不理 - 博客园

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

相关文章:

重生之数据结构与算法----数组链表

简介 数据结构的本质&#xff0c;只有两种结构&#xff0c;数组与链表。其它的都是它的衍生与组合算法的本质就是穷举。 数组 数组可以分为两大类&#xff0c;静态数组与动态数组。静态数组的本质是一段连续的内存&#xff0c;因为是连续的&#xff0c;所以我们可以采用偏移量的…...

计算机网络常见疑问

tcpip模型没有数据链路层&#xff0c;那课本学的五层模型数据链路层的流量控制可靠传输是事实还是理论&#xff1f; 在计算机网络中&#xff0c;TCP/IP模型与OSI五层模型的分层差异确实容易引发疑问&#xff0c;尤其是关于数据链路层&#xff08;五层模型&#xff09;的功能是…...

C++07(继承)

文章目录 面向对象之继承继承相关概念派⽣类声明派⽣类的成员访问属性派⽣类的构造函数与析构函数 面向对象编程编程思想面向对象编程涉及到两个重要的概念类类型的定义**类中数据成员的定义**构建对象成员访问成员访问修饰符——限制成员的可见性构造函数析构函数静态成员共用…...

文件上传漏洞:upload-labs靶场1-10

目录 文件上传漏洞介绍 定义 产生原因 常见危害 漏洞利用方式 upload-labs详解 pass-01 pass-02 pass-03 pass-04 pass-05 pass-06 pass-07 pass-08 pass-09 pass-10 文件上传漏洞介绍 定义 文件上传漏洞是指网络应用程序在处理用户上传文件时&#xff0c;没有…...

【Python/Pytorch】-- 创建3090Ti显卡所需环境

文章目录 文章目录 01 服务器上&#xff0c;存在三个anaconda&#xff0c;如何选择合适的&#xff0c;创建python环境&#xff1f;02 conda、anaconda、cuda、cudnn区别03 用到一些指令04 如何指定cuda的版本&#xff1f;05 conda跟pip的区别&#xff1f;06 pycharm控制台07 服…...

自然语言转SQL之Vanna.ai:AI集成数据库

自然语言转SQL之Vanna.ai&#xff1a;AI集成数据库 一、Vanna.ai是什么二、落地步骤&#xff1a;实现三层需求2.1 官方示例看效果2.2 对接自己的数据库2.3 完全本地化之路 三、构建自己的产品3.1 提问转SQL3.2 执行SQL查询实例2 要实现的功能就是&#xff1a;用中文语言同数据库…...

【零基础到精通Java合集】第二十二集:CMS收集器详解(低延迟的里程碑)

课程标题:CMS收集器详解——低延迟垃圾回收的经典实现(15分钟) 目标:掌握CMS核心工作原理、适用场景与调优策略,理解其在高并发场景下的价值与局限性 0-1分钟:课程引入与CMS设计目标 以“高速公路不停车收费”类比CMS核心思想:在用户线程运行的同时并发回收垃圾,最大…...

2025-03-04 学习记录--C/C++-PTA 习题5-5 使用函数统计指定数字的个数

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ #include <stdio.h>int CountDigit( int number, int di…...

SP导入模型设置

法线贴图格式 Blender,Unity选择OpenGL UE,3DMax选择DirectX...

计算机网络——IP地址

一、IP地址是什么&#xff1f; 定义 IP地址是互联网协议&#xff08;Internet Protocol&#xff09;为每台联网设备分配的唯一标识符&#xff0c;由一串数字&#xff08;IPv4&#xff09;或字母与数字组合&#xff08;IPv6&#xff09;构成。 核心作用&#xff1a;定位设备位置…...

openharmony 软总线-设备发现流程

6.1 设备发现流程 6.1.1 Wi-Fi设备发现 6.1.1.1 Wi-Fi设备发现流程 Wi-Fi设备在出厂状态或者恢复出厂状态下&#xff0c;设备上电默认开启SoftAP模式&#xff0c;SoftAP的工作信道在1&#xff0c;6&#xff0c;11中随机选择&#xff0c;SoftAP的Beacon消息中携带的SSID eleme…...

零信任架构和传统网络安全模式的

零信任到底是一个什么类型的模型&#xff1f;什么类型的思想或思路&#xff0c;它是如何实现的&#xff0c;我们要做零信任&#xff0c;需要考虑哪些问题&#xff1f; 零信任最早是约翰金德瓦格提出的安全模型。早期这个模型也是因为在安全研究上考虑的一个新的信任式模型。他最…...

TCP/IP四层模型:从入门到精通

第一部分&#xff1a;基础概念 1.1 什么是TCP/IP&#xff1f; - TCP/IP 是互联网的基础通信协议簇&#xff0c;定义了数据如何在网络中传输和路由。 - 与OSI七层模型的对比&#xff1a;TCP/IP更简化&#xff0c;分为四层&#xff0c;注重实际应用。 1.2 四层模型结构 1. 应…...

二、QT和驱动模块实现智能家居-----问题汇总1

1、文件地址改变后必须在QT下更改地址 2、指定了QT内Kits下的Sysroot头文件地址&#xff0c;但是还是找不到头文件&#xff1a; 3、提示无法执行QT程序&#xff1a;先干掉之前的QT程序 ps //查看程序PIDkill -9 PID 4、无法执行QT程序 1&#xff09;未设置环境变量 …...

10、HTTP/3有了解过吗?【中高频】

HTTP/2 虽然具有多个流并发传输的能力&#xff0c;但是传输层是 TCP 协议&#xff0c;依然存在缺陷&#xff1a; 队头阻塞&#xff0c;HTTP/2 是基于 TCP 协议来传输数据的&#xff0c;TCP 是字节流协议&#xff0c;TCP 层必须保证收到的字节数据是完整、连续的&#xff0c;当「…...

基于https虚拟主机配置

一、https介绍 http 明文&#xff0c;80/tcp https 密文&#xff0c;443/tcp 二、安全性保障 1、数据安全性 数据加密 2、数据完整性 3、验证身份的真实性、有效性 三、数据安全性 手段&#xff1a;加密 发送方加密数据&#xff0c;接收方解密数据 对称加密算法 加密、解密数据…...

小白入坑向:Java 全栈系统性学习推荐路线之一

文章目录 一、 引言1.1 学习路径&#xff1a;1.2 技术栈全景概述1.3 前沿技术与趋势预判 二、 前端篇2.1 基础知识2.2 进阶技术2.3 前端框架与工具 三、 后端篇3.1 Java 基础3.2 进阶与新特性 四、 企业级框架与开发工具4.1 构建与项目管理4.2 核心框架4.3 数据持久层4.4 微服务…...

云原生存储架构:构建数据永续的新一代存储基础设施

引言&#xff1a;重新定义数据基础设施边界 蚂蚁集团基于Ceph构建的全闪存存储集群达到EB级规模&#xff0c;单集群IOPS突破1亿&#xff0c;延迟稳定在200μs内。Snowflake的存储计算分离架构使其数据湖查询速度提升14倍&#xff0c;存储成本降低82%。Gartner预测到2025年70%企…...

QTableWidget之表格列的隐藏与显示(折叠)

今天晚上花点时间研究一下表格列的显隐问题&#xff08;类似与excel的隐藏列功能&#xff09;&#xff0c;在网络上搜罗了一通资料&#xff0c;没现成的例子作为借鉴&#xff0c;只能自己研究编写了。现在将过程记录下来&#xff0c;以便日后翻阅。 首先声明&#xff1a;因为时…...

Leetcode3146. 两个字符串的排列差

题目描述&#xff1a; 给你两个字符串 s 和 t&#xff0c;每个字符串中的字符都不重复&#xff0c;且 t 是 s 的一个排列。 排列差 定义为 s 和 t 中每个字符在两个字符串中位置的绝对差值之和。 返回 s 和 t 之间的 排列差 。 代码思路&#xff1a; 建立字符位置映射&…...

Seedance2.0内容创作干货!学会这四点教你用 Seedance 2.0 拍出电影感!

Seedance 2.0 之所以能把商业广告、影视制作的质感拉满&#xff0c;核心在于它对“全参调用”的支持。想彻底驯服它&#xff0c;建议你在输入 Prompt 和参数时注意以下四点&#xff1a;1. 结构化你的提示词不要把所有想法堆砌成一句话。Seedance 2.0 对结构化文本的理解极强&am…...

良心云服务器部署的AI应用如何借助Taotoken实现多模型降级策略

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 良心云服务器部署的AI应用如何借助Taotoken实现多模型降级策略 在生产环境中&#xff0c;部署于云服务器上的AI应用对服务的连续性…...

探索罗技鼠标宏:掌握PUBG压枪技术的完整路径

探索罗技鼠标宏&#xff1a;掌握PUBG压枪技术的完整路径 【免费下载链接】logitech-pubg PUBG no recoil script for Logitech gaming mouse / 绝地求生 罗技 鼠标宏 项目地址: https://gitcode.com/gh_mirrors/lo/logitech-pubg 在《绝地求生》这款竞技性极强的射击游戏…...

联发科MT6873核心板:5G安卓设备开发实战与硬件设计指南

1. 项目概述&#xff1a;MT6873核心板&#xff0c;一款为智能终端注入5G灵魂的“心脏”在智能硬件开发领域&#xff0c;选对一颗“心脏”——也就是核心板或主控模块&#xff0c;往往决定了整个产品的性能上限、功能边界和市场竞争力。今天要深入聊的&#xff0c;就是联发科&am…...

Nano-vLLM 源码解读 - 9. 抢占机制

nano-vllm 用千行代码拆解 vLLM 核心,是读懂大模型推理最快的捷径。 L07 第 5 节讲过 schedule() 的 decode 分支大致结构,其中提到一句:“decode 在块边界处可能装不下,装不下就走 preempt”,当时把细节明确推迟到本节。 那段代码不到 10 行,却同时回答三个问题:decode 在什么…...

【Windows版Redis安装本地使用】

本地安装运行 一、Redis官网 二、下载 三、配置redis服务 一、Redis官网 官网: redis 二、下载 下载版本:版本下载 下载完后,解压文件到文件夹 三、配置redis服务 打开目录对应的终端 安装redis服务 redis-server.exe --service-install redis.windows.conf --loglevel verbos…...

STM32图像识别实战:从传统CV到TinyML的边缘AI部署

1. 项目概述&#xff1a;当STM32遇上图像识别在嵌入式开发领域&#xff0c;STM32系列微控制器因其出色的性能、丰富的外设和极高的性价比&#xff0c;早已成为工程师和爱好者的“瑞士军刀”。从简单的LED闪烁到复杂的电机控制、通信协议栈&#xff0c;STM32几乎无所不能。但提到…...

手把手教你用MP1470芯片设计一个12V转5V的DCDC降压模块(附完整原理图与PCB布局避坑指南)

手把手教你用MP1470芯片设计一个12V转5V的DCDC降压模块&#xff08;附完整原理图与PCB布局避坑指南&#xff09; 在嵌入式系统开发中&#xff0c;稳定可靠的电源设计往往是项目成功的关键前提。当我们需要为STM32、ESP32等微控制器或各类传感器供电时&#xff0c;如何将常见的1…...

Bilibili视频转文字完整指南:一键将B站视频转为可编辑文字稿

Bilibili视频转文字完整指南&#xff1a;一键将B站视频转为可编辑文字稿 【免费下载链接】bili2text Bilibili视频转文字&#xff0c;一步到位&#xff0c;输入链接即可使用 项目地址: https://gitcode.com/gh_mirrors/bi/bili2text 你是否曾为观看Bilibili视频时需要做…...

2026全球AI公司终极排名:从字节跳登顶到Claude Code称霸,十大巨头全维对比

2026全球AI公司终极排名:从字节跳登顶到Claude Code称霸,十大巨头全维对比 从字节跳动登顶到SpaceX 600亿美元收购Cursor&#xff0c;2026年的AI牌桌已经彻底重洗。本文带你一次性搞清全球AI格局。 目录 2026全球AI公司权威排名十大AI公司深度介绍AI编程助手终极对比AI Agent…...