AVL的删除写法的一个错误
今天在写AVL删除的时候犯了一个傻逼错误,调了很久,教训惨痛,引以为鉴。
树中允许有重复节点,如果删除的节点有重复,则只删除1个。
AVL删除采取的方法是首先判断待删除节点是否存在,如果存在,那么判断该节点是否有两个儿子,如果有,则找到它左子树中的最大节点,设其值为t,将之删除,并将它的值去覆盖待删除节点。此处删除函数是带返回值的,为删除的节点的值。但是如果树中节点可以重复出现,碰巧待删除节点有多个,那么这些节点的值可能有多个被t覆盖,导致发生错误。
那么怎么避免这一错误呢?
当然我们可以把重复的节点弄成一个节点,用一个cnt来标记它出现的次数。
或者,在将t覆盖带删除节点,保证只覆盖一次。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
#define MAXN 100055
int root,tot=0,n,m;
char opt[10];
struct node
{int ch[2],val,h,sz;
}tree[MAXN];
void update(int r)
{
tree[r].h=max(tree[tree[r].ch[0]].h,tree[tree[r].ch[1]].h)+1;
tree[r].sz=tree[tree[r].ch[0]].sz+tree[tree[r].ch[1]].sz+1;
}
void zig(int &r) //鍙虫棆
{
int t=tree[r].ch[0];
if(t==0)return;
tree[r].ch[0]=tree[t].ch[1];
tree[t].ch[1]=r;
update(r);
update(t);
r=t;
}
void zag(int &r)
{
int t=tree[r].ch[1];
if(t==0)return;
tree[r].ch[1]=tree[t].ch[0];
tree[t].ch[0]=r;
update(r);
update(t);
r=t;
}
void zigzag(int &r)
{
zig(tree[r].ch[1]);
zag(r);
}
void zagzig(int &r)
{
zag(tree[r].ch[0]);
zig(r);
}
bool find(int r,int x)
{
if(r==0)return 0;
if(tree[r].val==x)
return 1;
else if(tree[r].val<x)
return find(tree[r].ch[1],x);
else
return find(tree[r].ch[0],x);
}
void insert(int &r,int x)
{
if(r==0)
{tree[++tot].val=x;
tree[tot].sz=1;
tree[tot].h=1;
r=tot;
return;
}
if(x<=tree[r].val)
{
insert(tree[r].ch[0],x);
if(tree[tree[r].ch[0]].h==tree[tree[r].ch[1]].h+2)
{
if(x<=tree[tree[r].ch[0]].val)
zig(r);
else
zagzig(r);
}
}
else
{
insert(tree[r].ch[1],x);
if(tree[tree[r].ch[1]].h==tree[tree[r].ch[0]].h+2)
{
if(x>tree[tree[r].ch[1]].val)
zag(r);
else
zigzag(r);
}
}
update(r); }
void maintain(int &r)
{
if(r==0)return;
if(tree[tree[r].ch[0]].h==tree[tree[r].ch[1]].h+2)
{
int t=tree[r].ch[0];
if(t==0)return;
if(tree[tree[t].ch[0]].h==tree[tree[r].ch[1]].h+1)
zig(r);
else zagzig(r);
}
else if(tree[tree[r].ch[1]].h==tree[tree[r].ch[0]].h+2)
{
int t=tree[r].ch[1];
if(t==0)return;
if(tree[tree[t].ch[1]].h==tree[tree[r].ch[0]].h+1)
zag(r);
else zigzag(r);
}
update(r);
}
int del(int &r,int x)
{
int temp;
if(tree[r].val==x||(tree[r].val<x&&tree[r].ch[1]==0)||(tree[r].val>x&&tree[r].ch[0]==0))
{
if(tree[r].ch[1]==0||tree[r].ch[0]==0)
{
temp=tree[r].val;
r=tree[r].ch[1]+tree[r].ch[0];
return temp;
}
else
{
temp=tree[r].val; //注意这里,这样保证待删除节点只删掉了一个。
tree[r].val=del(tree[r].ch[0],x);
}
}
else if(tree[r].val<x)
temp= del(tree[r].ch[1],x);
else temp=del(tree[r].ch[0],x);
maintain(r);
return temp;
}
int query(int r,int rk)//鎵炬帓鍚嶄负绗瑀k鐨勫厓绱?
{
if(r==0)return 0;
int t=tree[r].ch[0];
if(tree[t].sz>=rk)
return query(tree[r].ch[0],rk);
else if(tree[t].sz+1<rk)
return query(tree[r].ch[1],rk-tree[t].sz-1);
else return tree[r].val;
}
int main()
{
int t,u,rnk=0;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
{
scanf("%d",&t);
insert(root,t);
}
rnk=n;
for(int i=0;i<m;i++)
{
scanf("%s",opt);
if(opt[0]=='I')
{
rnk++;
scanf("%d",&t);
insert(root,t);
}
else if(opt[0]=='D')
{
scanf("%d",&t);
if(find(root,t))
{
del(root,t);
rnk--;
}
}
else if(opt[0]=='M')
{
scanf("%d%d",&t,&u);
if(find(root,t))
{
del(root,t);
insert(root,u);
}
}
else if(opt[0]=='Q')
{
printf("%d\n",query(root,(rnk+1)/2));
}
}
return 0;
}
AVL的删除写法的一个错误的更多相关文章
- 关于Java中的继承和组合的一个错误使用的例子
[TOC] 关于Java中的继承和组合的一个错误使用的例子 相信绝大多数人都比较熟悉Java中的「继承」和「组合」这两个东西,本篇文章就主要就这两个话题谈论一下.如果我某些地方写的不对,或者比较幼稚, ...
- Vim安装jedi-vim提示的一个错误
(仅为了提醒自己) 第一次的安装方法好像是通过 bundle安装的,好像是通过这个安装的并不是最新的版本,然后删除了通过下面的方法,最重要的是要执行 git submodule update --in ...
- 双缓冲绘图和窗口控件的绘制——ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误 .
双缓冲绘图和窗口控件的绘制 ---ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误 cheungmine 我们通常使用ATL COM组件,生成一个带窗口的ActiveX控件,然后 ...
- [20180904]工作中一个错误.txt
[20180904]工作中一个错误.txt --//昨天看我提交一份修改建议,发现自己写的sql语句存在错误.--//链接:http://blog.itpub.net/267265/viewspace ...
- MySQL删除数据库时的错误(errno: 39)
由于mysql数据库是默认区分大小写的,部署的时候发现多了一些重复的表,于是就把多余的表删掉了.可是,剩下的重复的表再删除时会提示:表不存在. 于是,想把数据库删掉重新创建,可是,得到了 ERROR ...
- makefile的一个错误:*** missing separator
原文转自:http://blog.sina.com.cn/s/blog_87c063060101c9yp.html 1.在写 多目录下makefile的时候,碰到一个错误提示,让我纠结许久,后面还是解 ...
- RDP 协议组件 X.224 在协议流中发现一个错误并且中断了客户端连接
如果你的服务器有如下错误: “RDP 协议组件 X.224 在协议流中发现一个错误并且中断了客户端连接.” 可能的有2种: 1:你试试能否能继续远程登陆,有可能你的远程登陆组件出现问题. 2:有人攻击 ...
- git 如何删除远程仓库的错误提交
前言 最近一个版本发生产环境以后,忘了把分支切回开发分支,直接在release分支上开发新功能提交了....于是就需要去删除远程仓库的错误提交. git命令行实现 1.强制返回上次的版本(~1回退到上 ...
- C#反序列化XML异常:在 XML文档(0, 0)中有一个错误“缺少根元素”
Q: 在反序列化 Xml 字符串为 Xml 对象时,抛出如下异常. 即在 XML文档(0, 0)中有一个错误:缺少根元素. A: 首先看下代码: StringBuilder sb = new Stri ...
随机推荐
- 写简单游戏,学编程语言-python篇:传说哥大战剧毒术士
上篇写的动画示例其实算不上一个游戏,顶多算是利用pygame进行的图形操作,今天着手实现一个小游戏:传说哥大战剧毒术士.名字很玄乎,其实就是最简单的一个射击游戏.好了废话不多说,先上截图吧: 一.初始 ...
- 【转】IP协议详解之子网寻址、子网掩码、构造超网
子网寻址 1. 从两级IP地址到三级IP地址 <1>. IP地址利用率有时很低. <2>. 给每一个物理网络分配一个网络号会使路由表变得太大而使网络性能变坏. <3> ...
- AMD系统中,virtualbox 不能为虚拟电脑打开一个新任务
我的电脑装的Genymotion,之前开发Andriod4.4版本的时候在Genymotion上都可以运行,可是开发Andriod5.0+的时候,Genymotion就不能运行了,究其原因,原来是Vi ...
- POM
代码的第一行是xml头,指定了该xml文档的版本和编码方式 project是所有pom.xml的根元素,还声明了一些POM相关的命名空间及xsd元素. modelVersion指定了当前POM模型的版 ...
- Excel中如何过滤复选框 How to filter checkbox column in Excel
有个笨笨的小伙伴最近老跟Excel过不去. 她新加了一列checkbox,还想filter别人有没有选.写代码又不会,怎么办. 1. 首先,加这个checkbox 2. 然后新建一列,把这个check ...
- SQL Server如何编辑超过前200行的数据
从SQL Server 2008开始,微软为了提高查询效率等原因,右键点击表时弹出菜单中默认没有"显示所有行",而以"选择前1000行"替代.这有时会为我们带来 ...
- JAVA并发框架之Semaphore实现生产者与消费者模型
分类: Java技术 锁和信号量(Semaphore)是实现多线程同步的两种常用的手段.信号量需要初始化一个许可值,许可值可以大于0,也可以小于0,也可以等于0. 如果大于0,表示 ...
- 理解MySQL——索引与优化
转自:理解MySQL——索引与优化 写在前面:索引对查询的速度有着至关重要的影响,理解索引也是进行数据库性能调优的起点.考虑如下情况,假设数据库中一个表有10^6条记录,DBMS的页面大小为4K,并存 ...
- 什么是 JSON ?
什么是 JSON ? JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JSON 独立于语言 JSON ...
- Java语言的安全性的体现
Java语言的安全性的体现 1.严格遵循面向对象的规范.这样封装了数据细节,只提供接口给用户.增加了数据级的安全性. 2.无指针运算.java中的操作,除了基本类型都是引用的操作.引用是不能进行增减运 ...