常规算法学习
算法
- 1. 排序算法
- 1. 归并排序
- 1.1 普通归并排序
- 1.2 优化后的归并排序(TimSort)
- 2. 插入排序
- 2.1 直接插入排序
- 2.2 二分插入排序
- 2.3 成对插入排序
- 3. 快速排序
- 3.1 单轴快速排序
- 3.2 双轴快排
- 4. 计数排序
- 2. 树
- 1. 红黑树(Red Black Tree)
- 1.1 红黑树的定义或者是约束条件
- 1.2 红黑树添加节点:
- 1.3 红黑树删除节点
1. 排序算法
1. 归并排序
1.1 普通归并排序
归并排序比较适用于处理较大规模的数据,且比较消耗内存。所以小规模的序列,一般不使用归并排序。
基本思想:
就是“分治”思想,先将序列元素拆解,然后归并,即合并相邻有序子序列。
1.2 优化后的归并排序(TimSort)
自适应、稳定、高效的排序算法,源自合并排序和插入排序。
我们来进行归并排序的时候,就进行了许多没必要的“分”,因为有些子序列本来就是有序的了,随而也导致没必要的“治”。TimSort就是为了解决这一缺陷而生。
Timsort的思想是,“分”的时候,直接从左往右,划分成各种不同长度的、有序的子序列(每个子序列叫做一个run,),然后对这些子序列进行归并,这样一来,复杂度就大大降低了。
有序的子序列(Run):递增的序列或者是严格递减的序列(保证算法的稳定性,递减的序列需要进行翻转)。
minRun:最小的有序子序列的长度。如果有一个run的长度没有达到minrun,那就要从run序列后面的元素进行二分插入放入到run中,直到run的长度达到最小minrun。
minrun的选择:16-64之间,数组的长度/minrun 略小于等于2的次幂。
子序列合并:
需要使用栈。从第一个run开始依次入栈,每入栈一次,就要检查:
直到栈中所有run都满足上述要求,继续将下一个run放入到栈中。最终合并成一个。(为什么上图这么合并:如果违反了下面的两条规则,则Y与X、Z中的较小者合并。规则使得合并保持近似平衡,同时在延迟合并以实现平衡)
2. 插入排序
2.1 直接插入排序
基本思想:序列分为两部分,一部分有序,一部分无序,不断从无序的部分选元素出来,插入到有序的部分。(一开始是认为第一个元素是有序的部分,其他元素都是无序的部分)
插入排序一般应用于数据量较小的序列排序中。因为插入排序在小数组中已经表现的很好了。
2.2 二分插入排序
与直接插入排序不同点是:直接插入排序是待插入的元素依次和前一个元素进行比较、交换,直到满意位为止;二分插入排序是先从有序数组中通过二分查找确定待插入的位置,然后将后面的元素依次后移一位,并将带插入元素插入其中。减少了比较次数。
2.3 成对插入排序
在直接插入排序里面,我们在进行插入的时候,需要在每次循环时,不断与有序的元素进行比较,直到找到合适位置。而比较次数与移位次数是衡量一个算法优劣的标准。
成对插入排序是为了减少比较次数而生。
- 基本思想:
第一步:在无序部分拿两个元素a1,a2,并调整使a1>a2;
第二步:a1往左比较,找到合适位置后插入;
第三步:a2只需在a1的左边进行比较(a1>a2),找到合适的位置插入即可。
3. 快速排序
3.1 单轴快速排序
基本思想:
第一步:选其中一个元素出来作为轴。
第二步:两边同时开始遍历,比轴小的元素放在左边,比轴大的元素放在右边。
第三步:对上面被轴分开的两个序列,进行递归处理,重复执行一二步。最终得到一个有序序列
3.2 双轴快排
单轴很多时候可能会遇到较差的情况就是选取的元素可能是最大的或者最小的元素,这样元素就没办法将元素进行划分,时间复杂度也就变成了 T ( n ) = T ( n − 1 ) + O ( n ) , T ( n ) = O ( n 2 ) T(n) = T(n-1)+O(n), \quad T(n) = O(n^2) T(n)=T(n−1)+O(n),T(n)=O(n2)。
双轴快排,顾名思义,就是按两个轴,分成三个区。对于单轴快排,选取的轴是最大的或者最小的元素就会导致排序性能降低。对于双轴快排,只有两个轴一个选取最大,一个选取最小,才会使性能降低,这种概率比快排的概率小太多了。所以,双轴快排的优化力度还是挺大的。
选取待排序的最左侧、最右侧的两个数作为轴pivot1、pivot2,并且保证pivot1< pivot2,不满足就交换。通过交换数组中的元素,小于pivot1的元素放在pivot1左侧,大于pivot2的元素放在最右侧,在两者之间的放在中间。
然后,依次递归下去。
交换过程:
start和end一直不动,直到排好在进行交换。
4. 计数排序
计数排序适用于元素个数远大于元素种数的情况,适用于Short、Byte、Char等元素种数较少的类型。
基本思想:
①:先创建一个length为元素种数的数组count,里面的元素全部为0。
②:遍历要排序的序列,根据序列元素大小a找到数组count的位置,对count[a]+=1;
(举个例子:若刚好遍历到的元素是55,则找到count[55]+=1)
③:从左到右遍历count[],元素不是0的位置都拿出来,根据count[a]拿多少个。
④:最终得到有效序列。
2. 树
1. 红黑树(Red Black Tree)
1.1 红黑树的定义或者是约束条件
- 节点要么是红色要么是黑色
- 根节点必须是黑色
- 叶子节点挂两个空节点(逻辑上)是黑色
- 每个红色节点有两个黑色子节点,推导出一条路径上不能有两个连续的红色节点
- 每条路径上必须有相同数量的黑色节点
1.2 红黑树添加节点:
待插入节点是红色的,然后按照二叉搜索将待插入节点插入到叶子结点。
父节点叔节点 | 红色 | 黑色 |
---|---|---|
红色 | 变色(父节点、叔节点变黑,祖节点变红。然后把祖节点当做新插入的节点递归上述操作) | 无需操作 |
黑色 | 旋转(旋转完成之后,再根据变色原则,进行变色,这个过程中同样也会遇到旋转,但你已经明白了旋转的规律了。) | 无需操作 |
四种旋转情况(根据刚插入节点、父节点、祖节点的位置):
1.3 红黑树删除节点
首先看一下二叉搜索树删除节点操作:
先说一下如何删除二叉树查找树的节点吧。总共有三种情况
1.被删除的节点是叶子节点,这时候只要把这个节点删除,再把指向这个节点的父节点指针置为空就行
2.被删除的节点有左子树,或者有右子树,而且只有其中一个,那么只要把当前删除节点的父节点指向被删除节点的左子树或者右子树就行。
3.被删除的节点既有左子树而且又有右子树,这时候需要把左子树的最右边的节点或者右子树最左边的节点提到被删除节点的位置。
红黑树中删除一个节点,遇到的各种情形就是其子节点的状态和颜色的组合,子节点状态共有3种:无子节点、有一个子节点、有两个子节点,颜色有红色和黑色两种,所以共会有6种组合。
- 红黑树删除节点也要满足二叉搜索树的左小右大。因此,删除两个节点的情况和二叉搜索树的情况一样,转换成删除0个或者1个节点的情况。
- 只有一个子节点的情况,该节点不能是红色,只能是黑色。
可能出现的组合:
组合1:被删节点无子节点,且被删结点为红色
这是最简单的一种情况,直接将节点删除即可,不破坏任何红黑树的性质
组合2:被删结点无子结点,且被删结点为黑色
这是最复杂的情况,我们稍后再讨论
组合3:被删结点有一个子结点,且被删结点为黑色
这种组合下,被删结点node的另一个子结点value必然为红色,此时直接将node删掉,用value代替node的位置,并将value着黑即可。
再论组合2:被删结点无子结点,且被删结点为黑色
因为删除黑色结点会破坏红黑树的性质5,所以为了不破坏性质5,将node删除后用一个拥有额外黑色的null替代它(可以想象是将node删除后,在这个位置放了一个黑色的权值),剩下的就是调平的过程,最终这个游离的黑色权值被扔掉,整个删除操作完成。
然后再结合node的父结点father和其兄弟结点brother来分析。
情形一:brother为黑色,且brother有一个与其方向一致的红色子结点son
所谓方向一致,是指brother为father的左子结点,son也为brother的左子结点;或者brother为father的右子结点,son也为brother的右子结点。
情形二:brother为黑色,且brother有一个与其方向不一致的红色子结点son
转换成情形1,接着操作。
情形三:brother为黑色,且brother无红色子结点
此时若father为红,则重新着色即可,删除操作完成。
此时若father为黑,则重新着色,将游离的黑色权值存到father(此时father的黑色权重为2),将father作为新的结点进行情形判断,遇到情形一、情形二,则进行相应的调整,完成删除操作;如果没有,则结点一直上溯,直到根结点存储额外的黑色,此时将该额外的黑色扔掉,即完成了删除操作。(这个情景是最难的,好好理解)
情形四:brother为红色,则father必为黑色。
图(i)中,将brother和father旋转,重新上色后,变成了图(j),新的brother(原来的son)变成了黑色,这样就成了情形一、二、三中的一种。
图(i)中的情形颠倒过来,也是一样的操作。
总而言之,基本操作原则就是:一个黑色节点被删除之后,那么它的兄弟分支的节点分配给它一个或者是兄弟分支也减少一个,父节点从红色变黑色。
相关文章:

常规算法学习
算法 1. 排序算法1. 归并排序1.1 普通归并排序1.2 优化后的归并排序(TimSort) 2. 插入排序2.1 直接插入排序2.2 二分插入排序2.3 成对插入排序 3. 快速排序3.1 单轴快速排序3.2 双轴快排 4. 计数排序 2. 树1. 红黑树(Red Black Treeÿ…...

Google 发布的全新导航库:Jetpack Navigation 3
前言 多年来,Jetpack Navigation 库一直是开发者的重要工具,但随着 Android 用户界面领域的发展,特别是大屏设备的出现和 Jetpack Compose 的兴起,Navigation 的功能也需要与时俱进。 今年的 Google I/O 上重点介绍了 Jetpack Na…...

Arbitrum Stylus 合约实战 :Rust 实现 ERC20
在《Arbitrum Stylus 深入解析与 Rust 合约部署实战》篇中,我们深入探讨了 Arbitrum Stylus 的核心技术架构,包括其 MultiVM 机制、Rust 合约开发环境搭建,以及通过 cargo stylus 实现简单计数器合约的部署与测试。Stylus 作为 Arbitrum Nitr…...
电脑故障基础知识
1.1 了解电脑故障 分类:分为软件故障(系统感染病毒、程序错误)和硬件故障(硬件物理损坏、接触不良)。 原因:人为操作失误、病毒破坏、工作环境恶劣(高温 / 灰尘)、硬件老化。 准备工…...
12.2Swing中JButton简单分析
JButton 的继承结构 public class JButton extends AbstractButton implements Accessible AbstractButton 是所有 Swing 按钮类(如 JToggleButton, JRadioButton, JCheckBox)的基类。它封装了按钮的核心逻辑:图标、文本、边框、动作事件等…...

内存管理--《Hello C++ Wrold!》(8)--(C/C++)--深入剖析new和delete的使用和底层实现
文章目录 前言C/C内存分布new和deletenew和delete的底层定位new表达式 内存泄漏作业部分 前言 在C/C编程中,内存管理是理解程序运行机制的核心基础,也是开发高效、稳定程序的关键。无论是局部变量的存储、动态内存的分配,还是对象生命周期的…...
JavaScript性能优化实战指南(详尽分解版)
JavaScript性能优化实战指南 一、加载优化 减少HTTP请求 // 合并CSS/JS文件 // 使用雪碧图CSS Sprites .icon {background-image: url(sprites.png);background-position: -20px 0; }代码分割与懒加载 // 动态导入模块 button.addEventListener(click, async () > {cons…...
从 AMQP 到 RabbitMQ:核心组件设计与工作原理(一)
一、引言 ** 在当今分布式系统盛行的时代,消息队列作为一种关键的中间件技术,承担着系统间异步通信、解耦和削峰填谷的重要职责。AMQP(Advanced Message Queuing Protocol)作为一种高级消息队列协议,为消息队列的实现…...

Java进阶---JVM
JVM概述 JVM作用: 负责将字节码翻译为机器码,管理运行时内存 JVM整体组成部分: 类加载系统(ClasLoader):负责将硬盘上的字节码文件加载到内存中 运行时数据区(RuntimeData Area):负责存储运行时各种数据 执行引擎(Ex…...
鸿蒙OSUniApp离线优先数据同步实战:打造无缝衔接的鸿蒙应用体验#三方框架 #Uniapp
UniApp离线优先数据同步实战:打造无缝衔接的鸿蒙应用体验 最近在开发一个面向鸿蒙生态的UniApp应用时,遇到了一个有趣的挑战:如何在网络不稳定的情况下保证数据的实时性和可用性。经过一番探索和实践,我们最终实现了一套行之有效…...
地震资料裂缝定量识别——学习计划
学习计划 地震资料裂缝定量识别——理解常规采集地震裂缝识别方法纵波各向异性方法蚁群算法相干体及倾角检测方法叠后地震融合属性方法裂缝边缘检测方法 非常规采集地震裂缝识别方法P-S 转换波方法垂直地震剖面方法 学习计划 地震资料裂缝定量识别——理解 地震资料裂缝识别&a…...

C++ 检查一条线是否与圆接触或相交(Check if a line touches or intersects a circle)
给定一个圆的圆心坐标、半径 > 1 的圆心坐标以及一条直线的方程。任务是检查给定的直线是否与圆相交。有三种可能性: 1、线与圆相交。 2、线与圆相切。 3、线在圆外。 注意:直线的一般方程是 a*x b*y c 0,因此输入中只给出常数 a、b、…...
23. Merge k Sorted Lists
目录 题目描述 方法一、k-1次两两合并 方法二、分治法合并 方法三、使用优先队列 题目描述 23. Merge k Sorted Lists 方法一、k-1次两两合并 选第一个链表作为结果链表,每次将后面未合并的链表合并到结果链表中,经过k-1次合并,即可得到…...
每日算法刷题计划Day20 6.2:leetcode二分答案3道题,用时1h20min
9.3048.标记所有下标的最早秒数(中等) 3048. 标记所有下标的最早秒数 I - 力扣(LeetCode) 思想 1.给你两个下标从 1 开始的整数数组 nums 和 changeIndices ,数组的长度分别为 n 和 m 。 一开始,nums 中所有下标都是未标记的&a…...
Spring Security安全实践指南
安全性的核心价值 用户视角的数据敏感性认知 从终端用户角度出发,每个应用程序都涉及不同级别的数据敏感度。以电子邮件服务与网上银行为例:前者内容泄露可能仅造成隐私困扰,而后者账户若被操控将直接导致财产损失。这种差异体现了安全防护需要分级实施的基本原则: // 伪…...

Unity + HybirdCLR热更新 入门篇
官方文档 HybridCLR | HybridCLRhttps://hybridclr.doc.code-philosophy.com/docs/intro 什么是HybirdCLR? HybridCLR(原名 huatuo)是一个专为 Unity 项目设计的C#热更新解决方案,它通过扩展 IL2CPP 运行时,使其支持动态加载和…...
QuickBASIC QB64 支持 64 位系统和跨平台Linux/MAC OS
QuickBASIC 的现代继任者 QB64 已发展成为一个功能强大的开源项目,支持 64 位系统和跨平台开发。以下是详细介绍: 项目首页 - QB64pe:The QB64 Phoenix Edition Repository - GitCode https://gitcode.com/gh_mirrors/qb/QB64pe 1. QB64 概述 官网&am…...

ElasticSearch迁移至openGauss
Elasticsearch 作为一种高效的全文搜索引擎,广泛应用于实时搜索、日志分析等场景。而 openGauss,作为一款企业级关系型数据库,强调事务处理与数据一致性。那么,当这两者的应用场景和技术架构发生交集时,如何实现它们之…...

【C语言极简自学笔记】项目开发——扫雷游戏
一、项目概述 1.项目背景 扫雷是一款经典的益智游戏,由于它简单而富有挑战性的玩法深受人们喜爱。在 C 语言学习过程中,开发扫雷游戏是一个非常合适的实践项目,它能够综合运用 C 语言的多种基础知识,如数组、函数、循环、条件判…...
Global Security Markets 第5章知识点总结
一、章节核心内容概述 《Global Securities Markets》第五章聚焦全球主要证券交易所、关联存管机构及跨境交易实务,重点解析“乘客市场(Passenger Markets)”概念与合规风险,同时涵盖交易费用、监管规则等实操要点。考虑到市场的…...
电子电路:4017计数器工作原理解析
4017是CMOS十进制计数器/分频器,它属于CD4000系列,工作电压范围比较宽,可能3V到15V。我记得它有10个译码输出端,每个输出端依次在高电平和低电平之间循环,可能用于时序控制或者LED显示什么的。 4017内部应该由计数器和译码器两部分组成。计数器部分可能是一个约翰逊计数器…...
Vim 中设置插入模式下输入中文
在 Vim 中设置插入模式下输入中文需要配置输入法切换和 Vim 的相关设置。以下是详细步骤: 1. 确保系统已安装中文输入法 在 Linux 系统中,常用的中文输入法有: IBus(推荐):支持拼音、五笔等Fcitx…...
GitHub 趋势日报 (2025年05月31日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 1153 prompt-eng-interactive-tutorial 509 BillionMail 435 ai-agents-for-begin…...

Maven概述,搭建,使用
一.Maven概述 Maven是Apache软件基金会的一个开源项目,是一个有优秀的项目构建(创建)工具,它用来帮助开发者管理项目中的jar,以及jar之间的依赖关系,完成项目的编译,测试,打包和发布等工作. 我在当前学习阶段遇到过的jar文件: MySQL官方提供的JDBC驱动文件,通常命名为mysql-…...
基于大模型的数据库MCP Server设计与实现
基于大模型的数据库MCP Server设计与实现 引言 随着大语言模型(LLM, Large Language Model)能力的不断提升,AI Agent(智能体)正在从简单的对话问答,向更复杂的自动化任务执行和业务流程管理演进。在企业和开发者的实际需求中,数据库操作是最常见、最核心的场景之一。如…...
【前端】macOS 的 Gatekeeper 安全机制阻止你加载 bcrypt_lib.node 文件 如何解决
这个弹窗是 macOS 的 Gatekeeper 安全机制阻止你加载 bcrypt_lib.node 文件,因为它不是 Apple 签名的文件。 你想 “忽视” 它,其实是让系统允许这个 .node 原生模块运行,解决方式如下: sudo xattr -d com.apple.quarantine nod…...

Unity 环境搭建
Unity是一款游戏引擎,可用于开发各种类型的游戏和交互式应用程序。它由Unity Technologies开发,并在多个平台上运行,包括Windows、macOS、Linux、iOS、Android和WebGL。Unity也支持虚拟现实(VR)和增强现实(AR)技术,允许用户构建逼…...
【入门】【练9.3】 加四密码
| 时间限制:C/C 1000MS,其他语言 2000MS 内存限制:C/C 64MB,其他语言 128MB 难度:中等 分数:100 OI排行榜得分:12(0.1*分数2*难度) 出题人:root | 描述 要将 China…...

使用 SASS 与 CSS Grid 实现鼠标悬停动态布局变换效果
最终效果概述 页面为 3x3 的彩色格子网格;当鼠标悬停任意格子,所在的行和列被放大;使用纯 CSS 实现,无需 JavaScript;利用 SASS 的模块能力大幅减少冗余代码。 HTML 结构 我们使用非常基础的结构,9 个 .i…...
Node.js 全栈开发方向常见面试题
Node.js 全栈开发”方向的面试题**,这类岗位通常包括: 后端:Node.js(Express/Nest)、数据库、REST API、安全、部署等 前端:React/Vue(部分可能含 Next.js)、API 调用、状态管理等 …...