推出一个新系列,《看图轻松理解数据结构和算法》,主要使用图片来描述常见的数据结构和算法,轻松阅读并理解掌握。本系列包括各种堆、各种队列、各种列表、各种树、各种图、各种排序等等几十篇的样子。
关于树对于树的数据结构大家都了解,只是树的类型有很多,所以可能又会对树产生一种陌生感。树其实就是由有限n(n=1)个节点组成的一个具有层次关系的集合,它看起来像一棵倒挂的树,所以称之为“树”。
树的特点每个节点有若干个或0个子节点;
根节点没有父节点;
每一个非根节点有且只有一个父节点;
每个子节点可以分为多个不相交的子树;
二叉搜索树二叉搜索树(BinarySearchTree,简写BST),又称为二叉排序树,属于树的一种,通过二叉树将数据组织起来,树的每个节点都包含了健值key、数据值data、左子节点指针、右子节点指针。其中健值key是最核心的部分,它的值决定了树的组织形状;数据值data是该节点对应的数据,有些场景可以忽略,举个例子,key为身份证号而data为人名,通过身份证号找人名;左子节点指针指向左子节点;右子节点指针指向右子节点。
二叉搜索树特点左右子树也分别是二叉搜索树。
左子树的所有节点key值都小于它的根节点的key值。
右子树的所有节点key值都大于他的根节点的key值。
二叉搜索树可以为一棵空树。
一般来说,树中的每个节点的key值都不相等,但根据需要也可以将相同的key值插入树中。
image插入操作如果为空树则将插入节点作为根节点。
如果不为空树则从根节点开始,比较插入节点与根节点的key值,值相同则不做任何处理直接返回,大于则继续比较右子节点R,小于则继续比较左子节点L。
右子节点R与插入节点比较,插入节点的key值大的话则继续往R节点的右子节点比较,小于的话则继续往R节点左子节点比较。
以此类推不断往下寻找,直到找到左子节点指针或右子节点指针为空的节点,将插入节点放进去。
对于下面这棵树,插入D和H,
image创建D节点并与根节点比较,
imageD小于E,于是往左子节点继续比较,
imageD大于C,应该往右子节点方向,而此时C节点的右子节点指针为空,D节点可以放置进去。
image同样的,对于H节点,先创建H节点并与根节点比较,
imageH大于E,于是往右子节点继续比较,
imageH大于G,应该往右子节点方向,而此时G节点的右子节点指针为空,H节点可以放置进去。
image插入顺序性二叉搜索树的形状与节点插入顺序不同而可能不同,比如对于ABCDEFGH这些节点集,按ECABDGFH顺序插入则为,
image而如果调换前面两个节点,按照CEABDGFH顺序插入则如下图,形状差别还是挺大的,
image极端情况下,按照ABCDEFGH顺序插入,则为,
image查询操作则从根节点开始,比较查询节点与根节点的key值,值相同则表示找到该节点,直接返回,大于则继续往右子节点R查找,小于则继续往左子节点L查找。
右子节点R与查询节点比较,查询节点的key值大的话则继续往R节点的右子节点查找,小于的话则继续往R节点左子节点查找。
以此类推不断往下寻找,直到找到节点的key值与查询节点的相同,则表示查找成功,如果最终找不到则说明不存在该节点。
对于下图的树查找key值为“B”和“G”的节点,
image“B”与根节点的key值比较,
image“B”小于“E”,往左子节点继续寻找,
image“B”小于“C”,往左子节点继续寻找,
image“B”大于“A”,往右子节点继续寻找,两者相等,找到。
image继续查询key值为“G”的节点,与根节点比较,
image“G”大于“E”,往右子节点,两者相等,找到。
image删除操作删除操作分三种情况进行,
如果删除的节点为叶子节点,即它的左子节点指针和右子节点指针都为空时,则可以直接删掉该节点,并不会影响整棵树的结构。
如果删除的节点只有一个子节点(左子节点或右子节点),则直接将子节点提升到被删除的节点位置。
如果删除的节点有两个子节点,此时需要找到删除节点的中序后继或中序前驱来填补删除节点,中序后继其实就是所有大于删除节点中最小的那个,而中序前驱就是所有小于删除节点中最大的那个,因为二叉搜索树经过中序遍历后是一个递增序列,所以后继就是删除节点的后面那个节点,大于且大得最少的那个,比如中4就是3的后继。前驱就是删除节点前面那个节点,比如中2就是3的前驱。
情况一删除“B”叶子结点,从根节点开始查找,
imageimageimageimage找到,直接删除,
image情况二假如树的结构如下图,现在要删除“C”节点,
image从根节点开始找,
imageimage找到“C”节点,直接将原来指向“C”节点的右子节点指针指向“C”的子节点,
image最终为,
image情况三要在如下的树中删除“E”节点,
image“E”节点存在两个子节点,于是开始寻找“E”节点的中序前驱来替换它,前驱在左子节点“C”下最大值的那个节点,
image要找“C”节点下最大值节点则一直往右,
image直到不能继续往下,即“D”节点即是前驱,用“D”节点来替换“E”节点,
image最终实现将“E”节点删除。
image--------------------------------------
跟我交流:
-------------推荐阅读------------
我的开源项目汇总(机器深度学习、NLP、网络IO、AIML、mysql协议、chatbot)
为什么写《Tomcat内核设计剖析》
文章汇总——机器学习篇
文章汇总——Java及中间件
文章汇总——深度学习篇
文章汇总——JDK源码篇
文章汇总——自然语言处理篇
文章汇总——Java并发篇
wjseaboat有帮助,可赞赏
作者:梁凤洁/邱冠华
联系人:陈建宇/赵泽胤
来源:浙商证券银行研究团队
具体参见年1月27日报告《不良连双降,性价比之选——浦发银行年业绩快报点评》,如需报告全文或数据底稿,请联系团队成员或对口销售。
报告导读
浦发银行不良连续4个季度双降,当前21EPB0.54x,性价比突出。
投资要点
业绩概览
浦发银行年扣非净利润同比+0.6%,20Q4单季净利润同比+28.6%,单季增速环比+31pc;营收同比+3.0%,20Q4单季营收同比+7.5%,单季增速环比+11pc;ROE10.8%。20Q4不良率1.73%,环比-12bp;拨备覆盖率%,环比+3pc。
投资要点
1、利润增速提升。浦发银行20Q4单季净利润同比+29%,单季增速环比+31pc,利润增速迎来修复。推测是得益于规模扩张的加速(资产增速环比+1pc)和减值损失拖累的缓解。其中,营收单季同比+8%,增速环比+11pc,增速回升幅度为已披露快报的股份行中最大。展望未来,经济企稳改善下,年利润增速有望继续回升。
2、资产结构向好。浦发银行20Q4贷款环比20Q3增长6%,增速较总资产(环比+4%)快2pc,资产结构向好。负债端,存款增速进一步提升。20Q4末存款同比增长11%,增速环比提升1pc。
3、不良连续双降。浦发银行20Q4不良率环比-12bp至1.73%,达到年以来最低水平。不良余额环比-1.3%,不良连续4个季度实现双降。推测主要得益于经济恢复下,对公贷款的风险情况显著好转。拨备覆盖率环比+3pc至%,风险抵补能力提升。展望未来,经济修复有望带动资产质量进一步向好。
盈利预测及估值
浦发银行不良连续4个季度实现双降,且当前21EPB处于0.54x的低位,性价比突出。预计-年浦发银行归母净利润同比增速分别为+8.31%/+10.30%,对应EPS2.05/2.27元股。现价对应-年4.75/4.29倍PE,0.54/0.53倍PB。目标价12.00元,对应21年0.66xPB,买入评级。
风险提示
宏观经济失速,疫情二次反复,美国制裁风险。
报告正文
往期报告回顾
点击报告链接直达↓
行业专题
◇大行利润增速回0%确定性提升
◇春江水暖:第一份快报的启示
◇房贷新*:和风细雨,利好长远
◇信用债违约的影响及演进
◇三季报综述:业绩拐点!全年回0%?
◇中小银行定向*策的背后──兼评下调超储利率
◇房贷切换LPR专题:怎么选?影响几何?
◇当我们谈论存款降息时
策略报告◇浪来了,第三次要信
◇年度策略:与谁做时间的朋友
◇大象要起舞
◇翻多银行:否极,泰来!
◇银行策略:留一份清醒,留一份醉
◇中期策略:韬光养晦,以退为进
◇年度策略:大浪淘沙
◇年度策略:大浪淘沙估值篇——价格重于时间
个股研究
◇宁波银行:配股怎么看?
◇常熟银行:消化疫情影响,聚力普惠小微
◇长沙银行:业绩全面开花,中小银行翘楚
◇光大银行:最佳性价比银行
◇兴业银行:脱胎换骨,五年最佳
◇招商银行:标杆银行,王者风范
◇光大银行:利润增速提升,风险指标稳定
◇长沙银行:县域战略推进,市场份额提升
◇杭州银行:实际经营业绩大超预期
◇邮储银行:利润和资产质量双双超预期
◇南京银行:息差提升,风险向好
◇常熟银行:符合逾期,
王晓波
同程旅行机票事业群CTO
读完需要
12分钟速读仅需4分钟
本章和大家分享一下同程凤凰缓存系统在基于Redis方面的设计与实践。在本章中除了会列举我们工作过程中遇到各种问题和误区外,还会给出我们相应的解决办法,希望能够抛砖引玉为大家带来一定的启示。
本文节选自中生代技术社区出品图书《深入分布式缓存》
1
同程凤凰缓存系统遇到的问题
年~年,我们的业务开始使用一种新的互联网销售模式——秒杀抢购,一时间,各个产品线开始纷纷加人,今天秒杀门票,明天秒杀酒店。各种活动轮番登场,用户在不亦乐乎地玩着秒杀活动的同时,也对后端技术的支撑提出了一波又一波的挑战。
在第一个秒杀抢购系统上线后不久,流量越来越大,发现不对了:只要秒杀抢购一开始,卡顿、打不开的故障就会此起彼伏。一旦出现故障,所有人都急得直跳脚,因为秒杀抢购流量一下而过,没有机会补救。其实问题也很简单,一个有点经验的兄弟就很快就将问题定位出来:抢购那一下太耗费服务器资源,在同一时间段内涌入的人数大大超过了服务器的负载,服务器根本承受不了,CPU占用率很多时候都接近了%,请求的积压也很严重,从请求接人到数据的读取都有问题,尤以数据的读取最为严重。在原来的设计方式中虽然也考虑了大并发量下的数据读取,但是因为数据相对分散,读取时间相对拉长,不像秒杀抢购是对同一批或同一条数据进行超高并发的读取。当然秒杀抢购不仅仅是数据读取的集中并发,同时也是数据写入的集中并发。
问题是发现了,表面上看起来解决没那么简单。应用层的问题解决起来相对容易,实在不行多加点机器也能解决;但数据的问题就不是那么简单了,靠增加机器来解决是不行的。大部分关系型数据库没有真正的分布式解决方案,最多做一个主从分离或多加从库分担读取的压力。但因为秒杀抢购是数据集中式超高并发的读,所以一般的关系型数据库因为它本身局限性很难支撑这样瞬间突发的高并发,就算勉强顶上,也会因为秒杀抢购还有写的高并发,影响到读节点的数据同步问题。当然也可以拼命提升一下服务器的硬件性能,比如换最好的CPU、把硬盘换成SSD等等,但效果应该不会太显著,没有解决本质的问题,还比较费钱。
其实寻找新的解决方案也很简单,因为在当时那个年代的开源社区中有很多的NoSQL明星产品(如Redis等等)方案,这些方案也都提供了丰富的数据类型,拥有原子性操作和强大的并发性能特性,感觉简直就是为抢购量身定做的。于是我们也基于此做了一些方案,例如:数据在抢购活动开始前被先放到NoSQL数据库里,产生的订单数据先被放到队列中,
然后通过队列慢慢消化……这一系列的操作解决了抢购的问题,这里主要不是讲抢购技术方案,我们不再细化下去。
其实这样的解决方案在技术蛮荒时代还是相对靠谱的,在我们技术强壮的今天,这个方案还是单薄和弱小了一些,但是所有的技术点都是这样一路走来的。下面我们来看一下,从弱小走向长大,经历了哪些?
1.1
Redis用法的凌乱
从运维角度来想,Redis是很简单的东西,安装一下,配置一下,就轻松上线了,再加上Redis的一些单进程、单线程等特性,可以很稳定地给到应用层去随便使用。就像早期的我们,在很短的时间内,Redis实例部署达到了千个以上,用得多了真正的问题开始出现。什么问题?乱的问题。Redis从使用的角度来讲是需要像应用服务一样去治理的。为什么是需要治理的?我们先来看一些常见的运维与开发的聊天记录,大家会不会有一些风趣的感觉:
开发:“Redis为啥不能访问了?”运维:“刚刚服务器内存坏了,服务器自动重启了。”开发:“为什么Redis延迟这么久?”运维:“大哥,不要在Zset里面放几万条数据,插入排序的后果很严重啊!”开发:“我写进去的key呢,为什么不见了?”运维:“你的Redis超过最大大小了,不常用的key都丢了呀!”开发:“刚刚为啥读取全部失败了?”运维:“刚刚网络临时中断了一下,slave全同步了,在全同步完成之前,slave的读取全部失败。”开发:“我刚刚想到一个好方案,我需要GB的Redis,什么时候能准备好呢?”运维:“大哥,我们线上的服务器最大也就GB,别玩这么大好吗?”
光看这么一小点就感觉问题很多了,开发和运维都疲于奔命地解决这些看上去很无聊的问题。这些问题从本质上来讲还只是麻烦,谈不上困难。但是每当这些麻烦演变成一次Redis的故障时,哪怕是小故障,有时也会造成大痛苦,因为毕竟保存在内存里的数据太脆弱了,一不小心数据就会全部消失了。为此,当时也是绞尽脑汁,想了很多种办法
单机不是不安全吗?那么就开启主从+Keepalived,用虚IP地址在master和slave两边漂移,master挂了直接切换到slave。
数据放内存不是不安全吗?可以开启数据落盘,根据业务需要决定落盘规则,有AOF的,也有RDB的。
使用上不是有问题吗?那么多开几场培训,跟大家讲讲Redis的用法和规范。
以上策略在当时似乎很完美,但是没多久,均宣告失败,这是必然的。
为什么呢?先看那个主从+Keepalived的方案,这本来是个很好的方案,但是忽略了主数据节点挂掉的情况。我们在前面说过,Redis的单进程、单线程设计是其简单和稳定的基石,只要不是服务器发生了故障,在一般情况下是不会挂的。
但同时,单进程、单线程的设计会导致Redis接收到复杂指令时会忙于计算而停止响应,可能就因为一个Zset或者keys之类的指令,Redis计算时间稍长,Keepalived就认为其停止了响应,直接更改虚IP的指向,然后做一次主从切换。过不了多久,Zset和keys之类的指令又会从客户端发送过来,于是从机上又开始堵塞,Keepalived就一直在主从机之间不断地切换IP。终于主节点和从节点都堵了,Keepalived发现后,居然直接将虚IP释放了,然后所有的客户端都无法连接Redis了,只能等运维到线上手工绑定才行。
数据落盘也引起了很大的问题,RDB属于非阻塞式的持久化,它会创建一个子进程来专门把内存中的数据写人RDB文件里,同时主进程可以处理来自客户端的命令请求。但子进程内的数据相当于是父进程的一个拷贝,这相当于两个相同大小的Redis进程在系统上运行,会造成内存使用率的大幅增加。如果在服务器内存本身就比较紧张的情况下再进行RDB配置,内存占用率就会很容易达到%,继而开启虚拟内存和进行磁盘交换,然后整个Redis的服务性能就直线下降了。
另外,Zset、发布订阅、消息队列、Redis的各种功能不断被介绍,开发者们也在利用这些特性,开发各种应用,但从来没想过这么一个小小的Redis有这么多新奇的功能,它的缺点在什么地方,什么样的场景是不合适用的?
这时Redis在大部分的开发者手上就是像是一把锤子,看什么都是钉子,随时都一锤了事。同时也会渐渐地淡忘了开发的一些细节点和规范,因为用它解决性能的问题是那么轻松简单,于是一些基于Redis的新奇功能就接连不断地出现了:基于Redis的分布式锁、日志系统、消息队列、数据清洗,等等,各种各样的功能不断上线使用,从而引发了各种各样的问题。这时候原来那个救火神器就会变成
四处点火的神器,Redis堵塞、网卡打爆、连接数爆表等问题层出不穷,经过这么多折腾,Redis终于也变成了大家的噩梦了。
1.2
从实际案例再看Redis的使用
第一个案例
在一个炎热的夏天,引爆了埋藏已久的大炸弹。首先是一个产品线开发人员搭建起了一套庞大的价格存储系统,底层是关系型数据库,只用来处理一些事务性的操作和存放一些基础数据;在关系型数据库的上面还有一套MongoDB,因为MongoDB的文档型数据结构,让他们用起来很顺手,同时也可以支撑一定量的并发。在大部分情况下,一次大数据量的计算后结果可以重用但会出现细节数据的频繁更新,所以他们又在MongoDB上搭建了一层Redis的缓存,这样就形成了数据库→MongoDB→Redis三级的方式,对方案本身不评价,因为这不是本文重点,我们来看Redis这层的情况。由于数据量巨大,所以需要GB的Redis。并且在真实的调用过程中,Redis是请求量最大的点,当然如果Redis有故障时,也会有备用方案,从后面的MongoDB和数据库中重新加载数据到Redis,就是这么一套简单的方案上线了。
当这个系统刚开始运行的时候,一切都还安好,只是运维同学有点傻眼了,用GB的Redis单服务器去做,它的故障可能性太大了,所以大家建议将它分片,没分不知道,一分吓一跳,各种类型用得太多了,特别是里面还有一些类似消息队列使用的场景。由于开发同学对Redis使用的注意点
作者:梁凤洁/邱冠华
联系人:陈建宇
来源:浙商证券银行研究团队
具体参见年1月14日报告《脱胎换骨,五年最佳——兴业银行年业绩快报点评》,如需报告全文或数据底稿,请联系团队成员或对口销售。
报告导读
业绩大超预期,综合状态五年最佳,20见拐点,21开新局,重点推荐。
投资要点
数据概览
兴业银行年归母净利润同比+1.2%,增速环比20Q1-3提升6.7pc;营收同比+12.0%,增速环比提升0.9pc;ROE12.6%;不良率1.25%,环比-22bp;拨备覆盖率%,环比上升7pc。
数据点评
1、Q4营收增速或同行第一。Q4单季度利润、营收、拨备前利润增速分别为35%、15%、21%,分别较20Q3提升33pc、4pc和8pc。根据前三季度情况,推测兴业银行Q4单季营收增速大概率仍为股份行第一。核心驱动因素来看:①营收端,规模增速小幅上升,推测息差平稳改善、中收继续高速增长。②减值端,减值损失拖累下降,资产减值损失增速为30%,相较前三季度下降11pc。展望未来中收高增和风险改善将驱动盈利向好。
2、不良年来首次双降。20Q4末不良率环比大幅下降22bp至1.25%,创年以来最优水平,不良实现最近5年首次双降。一方面归因资产质量持续改善,另一方面加快加大处置、大幅夯实不良。20Q4贷款拨备覆盖率环比上升7pc至%,信贷和非信贷拨备同时增厚,家底进一步充实。预计年信用成本改善有望成为利润增长核心驱动力之一。
3、见拐点开新局。兴业银行资负结构和资产质量已发生了脱胎换骨的变化。年世纪疫情叠加百年变局,综合状态迎来最近五年最佳,实属不易、大超预期。随着商行+投行战略渐入佳境,年有望开新局、开好局。
盈利预测与估值
坚定看好兴业银行商行+投行战略,有望打造中国最佳综合金融服务银行。业绩大超预期,不良五年最佳,见拐点,开新局,重点推荐!预计-年兴业银行归母净利润同比增长+10.35%/+12.20%,对应EPS3.42/3.85元股,现价对应6.25/5.55倍PE,0.76/0.69倍PB。上调目标价至33.50元,现价空间57%,对应21年1.2xPB,买入评级。
风险提示
宏观经济失速,疫情二次反复,美国制裁风险。
报告正文
往期报告回顾
点击报告链接直达↓
行业专题
◇春江水暖:第一份快报的启示
◇房贷新*:和风细雨,利好长远
◇信用债违约的影响及演进
◇三季报综述:业绩拐点!全年回0%?
◇中小银行定向*策的背后──兼评下调超储利率
◇房贷切换LPR专题:怎么选?影响几何?
◇当我们谈论存款降息时
策略报告◇年度策略:与谁做时间的朋友
◇大象要起舞
◇翻多银行:否极,泰来!
◇银行策略:留一份清醒,留一份醉
◇中期策略:韬光养晦,以退为进
◇年度策略:大浪淘沙
◇年度策略:大浪淘沙估值篇——价格重于时间
个股研究
◇光大银行:利润增速提升,风险指标稳定
◇招商银行:零售业务加速修复
◇长沙银行:县域战略推进,市场份额提升
◇杭州银行:实际经营业绩大超预期
◇兴业银行:渐入佳境,蓄势待发
◇邮储银行:利润和资产质量双双超预期
◇南京银行:息差提升,风险向好
◇常熟银行:符合逾期,