堆与堆排序
一:如何理解“堆”
堆是一个完全二叉树; 完全二叉树要求除了最后一层,其他层的节点都是满的,最后一层的节点都靠左排列。
堆中每个节点都必须大于等于(或小于等于)其子树中每个节点的值。 堆中每个节点的值都大于等于(或者小于等于)其左右子节点的值。
对于每个节点的值都大于等于子树中每个节点值的堆,叫作“大顶堆”。对于每个节点的值都小于等于子树中每个节点值的堆,叫“小顶堆”。
二:如何实现“堆”要实现一个堆,要先知道堆都支持哪些操作,已及如何存储一个堆。
如何存储一个堆: 完全二叉树比较适合用数组来存储。用数组来存储完全二叉树是非常节省存储空间的。因为不需要存储左右子节点的指针,单纯地通过数组的下标,就可以找到一个节点的左右子节点和父节点。
往堆中插入一个元素 往堆中插入一个元素后,需要继续满足堆的两个特性
如果把新插入的元素放到堆的最后,则不符合堆的特性了,于是需要进行调整,让其重新满足堆的特性,这个过程叫做 堆化(heapify)
堆化实际上有两种,从下往上和从上往下
从下往上的堆化方法:堆化非常简单,就是顺着节点所在的路径,向上或者向下,对比,然后交换。
删除堆顶元素
从堆的定 ...
Redis数据类型对应的数据结构
Redis 中,键的数据类型是字符串,但是值的数据类型有很多,常用的数据类型是:字符串、列表、字典、集合、有序集合
列表(list)
列表这种数据类型支持存储一组数据
两种实现方法:(1)压缩列表(ziplist)(2)双向循环链表
当列表中存储的数据量比较小时,可以采用压缩列表的方式实现。
具体需要同时满足下面两个条件:(1)列表中保存的单个数据(可能是字符串类型的)小于 64 字节;(2)列表中数据个数少于 512 个
关于压缩列表
它并不是基础数据结构,而是 Redis 自己设计的一种数据存储结构
类似数组,通过一片连续的内存空间来存储数据
跟数组不同的是它允许存储的数据大小不同
压缩列表中的“压缩”如何理解?
“压缩”:就是节省内存,之所以说节省内存,是相较于数组的存储思路而言的。数组要求每个元素的大小相同,如果要存储不同长度的字符串,就需要用最大长度的字符串大小作为元素的大小。但压缩数组允许不同的存储空间。
压缩列表这种存储结构,另一方面可以支持不同类型数据的存储
数据存储在一片连续的内存空间,通过键来获取值为列表类型的数据,读取的效率也非常高。
不能同时满足压缩 ...
如何实现一个通用的高性能的排序函数
一、如何选择合适的排序算法?排序算法一览表
排序名称
时间复杂度
是稳定排序?
是原地排序?
冒泡排序
O(n^2)
是
是
插入排序
O(n^2)
是
是
选择排序
O(n^2)
否
是
快速排序
O(nlogn)
否
是
归并排序
O(nlogn)
是
否
桶排序
O(n)
是
否
计数排序
O(n+k)k是数据范围
是
否
基数排序
O(dn)d是纬度
是
否
为什选择快速排序?
线性排序时间复杂度很低但使用场景特殊,如果要写一个通用排序函数,不能选择线性排序。
为了兼顾任意规模数据的排序,一般会首选时间复杂度为O(nlogn)的排序算法来实现排序函数。
同为O(nlogn)的快排和归并排序相比,归并排序不是原地排序算法,所以最优的选择是快排。
二、如何优化快速排序?导致快排时间复杂度降为O(n)的原因是分区点选择不合理,最理想的分区点是:被分区点分开的两个分区中,数据的数量差不多。如何优化分区点的选择?有2种常用方法,如下:
三数取中法
从区间的首、中、尾分别取一个数,然后比较大小,取中间值作为分区点。
如果要排序的数组比较大,那 ...
归并排序与快速排序的PHP实现
一、分治思想
分治思想:分治,顾明思意,就是分而治之,将一个大问题分解成小的子问题来解决,小的子问题解决了,大问题也就解决了。
分治与递归的区别:分治算法一般都用递归来实现的。分治是一种解决问题的处理思想,递归是一种编程技巧。
二、归并排序
算法原理先把数组从中间分成前后两部分,然后对前后两部分分别进行排序,再将排序好的两部分合并到一起,这样整个数组就有序了。这就是归并排序的核心思想。如何用递归实现归并排序呢?写递归代码的技巧就是分写得出递推公式,然后找到终止条件,最后将递推公式翻译成递归代码。递推公式怎么写?如下递推公式:merge_sort(p…r) = merge(merge_sort(p…q), merge_sort(q+1…r))终止条件:p >= r 不用再继续分解
性能分析
算法稳定性:归并排序稳不稳定关键要看merge()函数,也就是两个子数组合并成一个有序数组的那部分代码。在合并的过程中,如果 A[p…q] 和 A[q+1…r] 之间有值相同的元素,那我们就可以像伪代码中那样,先把 A[p…q] 中的元素放入tmp数组,这样 就保证了值相同的元素,在合并前后的 ...
冒泡插入选择排序的php实现
一、排序方法与复杂度归类
几种最经典、最常用的排序方法:冒泡排序、插入排序、选择排序、快速排序、归并排序、计数排序、基数排序、桶排序。
复杂度归类
冒泡排序、插入排序、选择排序 O(n^2)
快速排序、归并排序 O(nlogn)
计数排序、基数排序、桶排序 O(n)
二、如何分析一个“排序算法”?算法的执行效率
最好、最坏、平均情况时间复杂度。
时间复杂度的系数、常数和低阶。
比较次数,交换(或移动)次数。
排序算法的稳定性
稳定性概念:如果待排序的序列中存在值相等的元素,经过排序之后,相等元素之间原有的先后顺序不变。
稳定性重要性:可针对对象的多种属性进行有优先级的排序。
举例:给电商交易系统中的“订单”排序,按照金额大小对订单数据排序,对于相同金额的订单以下单时间早晚排序。用稳定排序算法可简洁地解决。先按照下单时间给订单排序,排序完成后用稳定排序算法按照订单金额重新排序。
排序算法的内存损耗原地排序算法:特指空间复杂度是O(1)的排序算法。
三、冒泡排序冒泡排序只会操作相邻的两个数据。每次冒泡操作都会对相邻的两个元素进行比较,看是否满足大小关系要求,如果不满足就让它俩互换 ...
TCP-三次握手和四次挥手简单理解
三次握手(three-way handshaking)
在Google Groups的TopLanguage中看到一帖讨论TCP“三次握手”觉得很有意思。贴主提出“TCP建立连接为什么是三次握手?”的问题,在众多回复中,有一条回复写道:“这个问题的本质是, 信道不可靠, 但是通信双发需要就某个问题达成一致. 而要解决这个问题, 无论你在消息中包含什么信息, 三次通信是理论上的最小值. 所以三次握手不是TCP本身的要求, 而是为了满足”在不可靠信道上可靠地传输信息”这一需求所导致的. 请注意这里的本质需求,信道不可靠, 数据传输要可靠. 三次达到了, 那后面你想接着握手也好, 发数据也好, 跟进行可靠信息传输的需求就没关系了. 因此,如果信道是可靠的, 即无论什么时候发出消息, 对方一定能收到, 或者你不关心是否要保证对方收到你的消息, 那就能像UDP那样直接发送消息就可以了.”。这可视为对“三次握手”目的的另一种解答思路
背景:TCP位于传输层,作用是提供可靠的字节流服务,为了准确无误地将数据送达目的地,TCP协议采纳三次握手策略。
原理:
发送端首先发送一个带有SYN(syn ...
GIT远程仓库
要参与任何一个 Git 项目的协作,必须要了解该如何管理远程仓库。远程仓库是指托管在网络上的项目仓库,可能会有好多个,其中有些你只能读,另外有些可以写。同他人协作开发某个项目时,需要管理这些远程仓库,以便推送或拉取数据,分享各自的工作进展。 管理远程仓库的工作,包括添加远程库,移除废弃的远程库,管理各式远程库分支,定义是否跟踪这些分支,等等
查看当前远程仓库要查看当前配置有哪些远程仓库,可以用 git remote 命令,它会列出每个远程库的简短名字。在克隆完某个项目后,至少可以看到一个名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库:
12345678910$ git clone git://github.com/schacon/ticgit.gitCloning into 'ticgit'...remote: Reusing existing pack: 1857, done.remote: Total 1857 (delta 0), reused 0 (delta 0)Receiving o ...
哈希算法
带着问题来学习:
如何防止数据库中的用户信息被脱库?
你会如何存储用户密码这么重要的数据吗?仅仅 MD5 加密一下存储就够了吗?
在实际开发中,我们应该如何用哈希算法解决问题?
###一、什么是哈希算法?
定义将任意长度的二进制值串映射成固定长度的二进制值串,这个映射的规则就是哈希算法,而通过原始数据映射之后得到的二进制值串就是哈希值。
如何设计一个优秀的哈希算法?
单向哈希:从哈希值不能反向推导出哈希值(所以哈希算法也叫单向哈希算法)。
篡改无效:对输入敏感,哪怕原始数据只修改一个Bit,最后得到的哈希值也大不相同。
散列冲突:散列冲突的概率要很小,对于不同的原始数据,哈希值相同的概率非常小。
执行效率:哈希算法的执行效率要尽量高效,针对较长的文本,也能快速计算哈希值。
二、哈希算法的常见应用有哪些?7个常见应用:安全加密、唯一标识、数据校验、散列函数、负载均衡、数据分片、分布式存储。
安全加密
常用于加密的哈希算法:
MD5:MD5 Message-Digest Algorithm,MD5消息摘要算法
SHA:Secure Hash Algorithm,安全散列算法
D ...
PHP数组排序
一维数组排序sort() -以升序对数组进行排序rsort() -以降序对数组排序asort() -根据值,以升序对关联数组进行排序ksort() -根据键,以升序对关联数组进行排序arsort() -根据值,以降序对关联数组进行排序krsort() -根据键,以降序对关联数组进行排序
二维数组排序array_multisort()123456$idArr = [];foreach ($arr as $v) { $idArr[] = $v['like'];}array_multisort($idArr, SORT_DESC, $arr);return $arr;
usort()12345678usort($arr, function($a, $b) { $al = $a['like']; $bl = $b['like']; if ($al == $bl) return 0; return ($al > $bl) ? -1 : 1;});r ...
处理composer.lock文件合并冲突
多人协同开发过程中,如果同时新增或升级了依赖经常会遇到人工处理 composer.lock/json 文件冲突的情况,下面介绍个简单粗暴的处理方式:
1234# 按需回滚冲突文件到对方的版本git checkout --theirs -- composer.lock composer.json # 重新添加自己的依赖或升级composer require '...'
这样可以避免人工解冲突,可以无脑执行,并且不会造成无关包的升级。