常规算法学习

算法

  • 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(n1)+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. 根节点必须是黑色
  3. 叶子节点挂两个空节点(逻辑上)是黑色
  4. 每个红色节点有两个黑色子节点,推导出一条路径上不能有两个连续的红色节点
  5. 每条路径上必须有相同数量的黑色节点

1.2 红黑树添加节点:

待插入节点是红色的,然后按照二叉搜索将待插入节点插入到叶子结点。

父节点叔节点红色黑色
红色变色(父节点、叔节点变黑,祖节点变红。然后把祖节点当做新插入的节点递归上述操作)无需操作
黑色旋转(旋转完成之后,再根据变色原则,进行变色,这个过程中同样也会遇到旋转,但你已经明白了旋转的规律了。)无需操作

四种旋转情况(根据刚插入节点、父节点、祖节点的位置):

在这里插入图片描述
在这里插入图片描述

1.3 红黑树删除节点

首先看一下二叉搜索树删除节点操作

先说一下如何删除二叉树查找树的节点吧。总共有三种情况

1.被删除的节点是叶子节点,这时候只要把这个节点删除,再把指向这个节点的父节点指针置为空就行

2.被删除的节点有左子树,或者有右子树,而且只有其中一个,那么只要把当前删除节点的父节点指向被删除节点的左子树或者右子树就行

3.被删除的节点既有左子树而且又有右子树,这时候需要把左子树的最右边的节点或者右子树最左边的节点提到被删除节点的位置

红黑树中删除一个节点,遇到的各种情形就是其子节点的状态和颜色的组合,子节点状态共有3种:无子节点、有一个子节点、有两个子节点,颜色有红色和黑色两种,所以共会有6种组合。

  1. 红黑树删除节点也要满足二叉搜索树的左小右大。因此,删除两个节点的情况和二叉搜索树的情况一样,转换成删除0个或者1个节点的情况。
  2. 只有一个子节点的情况,该节点不能是红色,只能是黑色。

可能出现的组合:

组合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)中的情形颠倒过来,也是一样的操作。

总而言之,基本操作原则就是:一个黑色节点被删除之后,那么它的兄弟分支的节点分配给它一个或者是兄弟分支也减少一个,父节点从红色变黑色。

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

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

相关文章

关于线程死锁的相关知识

前言 今天学习了线程死锁的相关知识。线程死锁是非常重要的知识&#xff0c;写成博客&#xff0c;加深自己对于知识的理解。 线程死锁 结语 希望可以帮助到大家~

EMQX启用单向认证的SSl/TLS连接的配置步骤

先确保您已经安装了 OpenSSL 执行openssl version -a 获取 openssl.cnf 目录 生成自签名服务端证书 CA 证书生成 server-ca.crt openssl req \-new \-newkey rsa:2048 \-days 365 \-nodes \-x509 \-subj "/CCN/OEMQ Technologies Co., Ltd/CNEMQ CA" \-keyout s…

依赖nacos实例动态创建线程池并监听服务上下线

版本 Spring Booot 版本 3.2.4Spring Cloud 版本 2023.0.1Spring Cloud Alibaba 版本 2023.0.1.2 依赖 <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </depe…

全面指南:使用Node.js和Python连接与操作MongoDB

在现代Web开发中&#xff0c;数据库是存储和管理数据的核心组件。MongoDB作为一款流行的NoSQL数据库&#xff0c;以其灵活的数据模型、高性能和易扩展性广受开发者欢迎。无论是使用Node.js还是Python&#xff0c;MongoDB都提供了强大的官方驱动和第三方库&#xff0c;使得数据库…

LeetCode 3068.最大节点价值之和:脑筋急转弯+动态规划(O(1)空间)

【LetMeFly】3068.最大节点价值之和&#xff1a;脑筋急转弯动态规划&#xff08;O(1)空间&#xff09; 力扣题目链接&#xff1a;https://leetcode.cn/problems/find-the-maximum-sum-of-node-values/ 给你一棵 n 个节点的 无向 树&#xff0c;节点从 0 到 n - 1 编号。树以长…

HTTPS加密通信详解及在Spring Boot中的实现

HTTPS&#xff08;Hyper Text Transfer Protocol Secure&#xff09;是HTTP的安全版本&#xff0c;通过SSL/TLS协议为通讯提供加密、身份验证和数据完整性保护。 一、HTTPS核心原理 1.加密流程概述 客户端发起HTTPS请求&#xff08;连接到服务器443端口&#xff09;服务器返…

解决线程安全问题

前言 昨天学习了如何去解决线程不安全的问题。一般方法都是通过加锁来处理&#xff0c;跟大家分享一波 。 解决线程安全问题 结语 希望可以帮助到大家~ byebye

网络常识:网线和光纤的区别

网络常识&#xff1a;网线和光纤的区别 一. 介绍二. 网线2.1 什么是网线&#xff1f;2.2 网线的主要类别2.3 网线的优势2.4 网线的劣势 三. 光纤3.1 什么是光纤&#xff1f;3.2 光纤的主要类别3.3 光纤的优势3.4 光纤的劣势 四. 网线 vs 光纤&#xff1a;谁更适合你&#xff1f…

win11 禁用/恢复 内置笔记本键盘(保证管用)

文章目录 禁用启用 禁用 1&#xff09;按下 win x&#xff0c;点击 设备管理器 2&#xff09;拔掉所有笔记本外设&#xff08;一定要都拔掉&#xff0c;不然后面禁用设备会混淆&#xff09;&#xff0c;然后右键点击 键盘 > HID Keyboard Device 2&#xff09;点击 更新…

Three.js搭建小米SU7三维汽车实战(5)su7登场

汽车模型加载 我们在sktechfab上下载的汽车是glb的文件格式&#xff0c;所以使用gltfLoader进行加载。这里将小车直接加载进来看看效果&#xff1b; import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js"; ....其余代码省略 const gltfLoader new GLT…

ETL怎么实现多流自定义合并?

随着信息技术的迅猛发展以及数据生成环境的多样化&#xff0c;互联网、物联网和社交媒体的广泛应用导致各种设备和平台不断产生大量数据&#xff0c;需要整合这些数据&#xff0c;从而进行数据融合。数据集成和管理平台ETLCloud&#xff0c;主要用于支持数据的抽取&#xff08;…

数据结构- 10种常见树:二叉树、平衡二叉树、完全二叉树

一、树 树型结构是一类重要的非线性数据结构。其中以树和二叉树最为常用&#xff0c;直观看来&#xff0c;树是以分支关系定义的层次结构。把它叫做“树”是因为它常看起来像一棵倒挂的树&#xff0c;也就是说它常是根朝上&#xff0c;而叶朝下的。 1.树的定义&#xff1a; 树…

Java常用加密方式

一&#xff0c;加密算法分类 对称加密&#xff1a;指加密和解密的密钥相同&#xff0c;优点就是加解密的效率高且易于实现。 非对称加密&#xff1a;指加密和解密的密钥不相同&#xff0c;也称为公私要加密。 不可逆加密&#xff1a;特征就是加密过程不需要密钥&#xff0c;…

SQLite软件架构与实现源代码浅析

概述 SQLite 是一个用 C 语言编写的库&#xff0c;它成功打造出了一款小型、快速、独立、具备高可靠性且功能完备的 SQL 数据库引擎。本文档将为您简要介绍其架构、关键组件及其协同运作模式。 SQLite 显著特点之一是无服务器架构。不同于常规数据库&#xff0c;它并非以单独进…

让 Deepseek GPS测速

下面是一个简单的微信小程序GPS测速功能的实现代码&#xff0c;包括前端页面和后端逻辑。 1. 页面结构 (index.wxml) <view class"container"><view class"speed-display"><text class"speed-value">{{speed}}</text>…

什么是软件的生命周期,以及常见的开发测试模型

目录 一、软件的生命周期 1、什么是生命周期&#xff1f; 2、每个阶段都要做些什么&#xff1f; 二、常见的开发模型 1、瀑布模型 2、螺旋模型 3、增量模型、迭代模型 4、敏捷模型 scrum模型 三个角色 五个会议 一、软件的生命周期 1、什么是生命周期&#xff…

JWT安全:弱签名测试.【实现越权绕过.】

JWT安全&#xff1a;假密钥【签名随便写实现越权绕过.】 JSON Web 令牌 (JWT)是一种在系统之间发送加密签名 JSON 数据的标准化格式。理论上&#xff0c;它们可以包含任何类型的数据&#xff0c;但最常用于在身份验证、会话处理和访问控制机制中发送有关用户的信息(“声明”)。…

数据分析与应用-----使用scikit-learn构建模型

目录 一、使用sklearn转换器处理数据 &#xff08;一&#xff09;、加载datasets模块中的数据集 &#xff08;二&#xff09;、将数据集划分为训练集和测试集 ​编辑 train_test_spli &#xff08;三&#xff09;、使用sklearn转换器进行数据预处理与降维 PCA 二、 构…

【Tomcat】Tomcat端口仅允许本地访问设置方法

要设置Tomcat端口仅允许本地访问&#xff0c;可以通过以下两种主要方式实现&#xff1a; 方法一&#xff1a;修改Tomcat配置文件&#xff08;推荐&#xff09; 修改 server.xml 文件 打开Tomcat的配置文件 conf/server.xml&#xff0c;找到 <Connector> 标签&#xff08;…

arcgis字段计算器中计算矢量面的每个点坐标

python脚本 函数 def ExportCoordinates(feat):coors = []partnum = 0partcount = feat.partCountwhile partnum < partcount:part = feat.getPart(partnum)pnt = part.next()while pnt:coors.append("({}, {})".format(pnt.X,pnt.Y))pnt = part.next()if not p…