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 ...
随机推荐
- Java常用的输入输出方法
对于经常上机刷题的来说,首先得解决输入输出方法,Java的输入输出流在Java学习过程的后面部分才会接触,但是我们可以掌握一些简单的,常用的输入输出方法 首先输出 大家最熟悉的莫过于输出方法,直接用S ...
- AI第二次作业
2.9 设有如下语句,请用相应的谓词公式分别把它们表示出来: (1)有的人喜欢梅花,有的人喜欢菊花,有的人既喜欢梅花又喜欢菊花. 解:设 P(x): x是人 L(x,y): x喜 ...
- react native 之 react-native-image-picke的详细使用图解
最近需要在react native项目中集成相机和相册的功能,于是在网上找了一个好用的第三方插件:react-native-image-picke. 该插件可以同时给iOS和Android两个平台下使 ...
- C# foreach,等量代换,冒泡排序
foreach: foreach (int h in a) //可以将数组读出来(自动遍历数组) { Console.WriteLi ...
- jquery 操作
Jquery使用时要引用,引用时放在最前. Jquery: $代表选择器, $(document) ready(function(e){}):找到页面,页面加载完成后执行. JS选取元素操作内容操作属 ...
- span标签设置margin-top没有效果
<span>是行内元素,span只有margin-left和margin-right才有效果.要想margin-top生效就要把span转给块级元素才行.在span的css中加入以下属性即 ...
- VIM-Sed常用的一些记录。。。逐渐学习。。
:[range]co[py] {address} :t :[range]m[ove] {address] 例如 :1,3t10 1-3行复制到10行后.用m就是移动了. :sort / / // ...
- php字符串处理函数大全
addcslashes - 为字符串里面的部分字符添加反斜线转义字符addslashes - 用指定的方式对字符串里面的字符进行转义bin2hex - 将二进制数据转换成十六进制表示chop - ...
- MediaCodec Name & Type
OMX.google.mp3.decoder support type:audio/mpegOMX.google.amrnb.decoder support type:audio/3gppOMX.go ...
- ueditor 上传的图片在内容里显示的尺寸过大的问题
没改动之前是上面这样的,图片显示不开,撑出了滚动条,想让他自适应100%,不出现滚动条 网上有方法 1.ueditor 的 themes 文件夹下有个iframe.css 加入以下代码,保存(原先的c ...