今天在写AVL删除的时候犯了一个傻逼错误,调了很久,教训惨痛,引以为鉴。

树中允许有重复节点,如果删除的节点有重复,则只删除1个。

AVL删除采取的方法是首先判断待删除节点是否存在,如果存在,那么判断该节点是否有两个儿子,如果有,则找到它左子树中的最大节点,设其值为t,将之删除,并将它的值去覆盖待删除节点。此处删除函数是带返回值的,为删除的节点的值。但是如果树中节点可以重复出现,碰巧待删除节点有多个,那么这些节点的值可能有多个被t覆盖,导致发生错误。

那么怎么避免这一错误呢?

当然我们可以把重复的节点弄成一个节点,用一个cnt来标记它出现的次数。

或者,在将t覆盖带删除节点,保证只覆盖一次。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cstdlib>
  5. using namespace std;
  6. #define MAXN 100055
  7. int root,tot=0,n,m;
  8. char opt[10];
  9. struct node
  10. {int ch[2],val,h,sz;
  11. }tree[MAXN];
  12. void update(int r)
  13. {
  14. tree[r].h=max(tree[tree[r].ch[0]].h,tree[tree[r].ch[1]].h)+1;
  15. tree[r].sz=tree[tree[r].ch[0]].sz+tree[tree[r].ch[1]].sz+1;
  16. }
  17. void zig(int &r) //鍙虫棆
  18. {
  19. int t=tree[r].ch[0];
  20. if(t==0)return;
  21. tree[r].ch[0]=tree[t].ch[1];
  22. tree[t].ch[1]=r;
  23. update(r);
  24. update(t);
  25. r=t;
  26. }
  27. void zag(int &r)
  28. {
  29. int t=tree[r].ch[1];
  30. if(t==0)return;
  31. tree[r].ch[1]=tree[t].ch[0];
  32. tree[t].ch[0]=r;
  33. update(r);
  34. update(t);
  35. r=t;
  36. }
  37. void zigzag(int &r)
  38. {
  39. zig(tree[r].ch[1]);
  40. zag(r);
  41. }
  42. void zagzig(int &r)
  43. {
  44. zag(tree[r].ch[0]);
  45. zig(r);
  46. }
  47. bool find(int r,int x)
  48. {
  49. if(r==0)return 0;
  50. if(tree[r].val==x)
  51. return 1;
  52. else if(tree[r].val<x)
  53. return find(tree[r].ch[1],x);
  54. else
  55. return find(tree[r].ch[0],x);
  56. }
  57. void insert(int &r,int x)
  58. {
  59. if(r==0)
  60. {tree[++tot].val=x;
  61. tree[tot].sz=1;
  62. tree[tot].h=1;
  63. r=tot;
  64. return;
  65. }
  66. if(x<=tree[r].val)
  67. {
  68. insert(tree[r].ch[0],x);
  69. if(tree[tree[r].ch[0]].h==tree[tree[r].ch[1]].h+2)
  70. {
  71. if(x<=tree[tree[r].ch[0]].val)
  72. zig(r);
  73. else
  74. zagzig(r);
  75. }
  76. }
  77. else
  78. {
  79. insert(tree[r].ch[1],x);
  80. if(tree[tree[r].ch[1]].h==tree[tree[r].ch[0]].h+2)
  81. {
  82. if(x>tree[tree[r].ch[1]].val)
  83. zag(r);
  84. else
  85. zigzag(r);
  86. }
  87. }
  88. update(r);
  89.  
  90. }
  91. void maintain(int &r)
  92. {
  93. if(r==0)return;
  94. if(tree[tree[r].ch[0]].h==tree[tree[r].ch[1]].h+2)
  95. {
  96. int t=tree[r].ch[0];
  97. if(t==0)return;
  98. if(tree[tree[t].ch[0]].h==tree[tree[r].ch[1]].h+1)
  99. zig(r);
  100. else zagzig(r);
  101. }
  102. else if(tree[tree[r].ch[1]].h==tree[tree[r].ch[0]].h+2)
  103. {
  104. int t=tree[r].ch[1];
  105. if(t==0)return;
  106. if(tree[tree[t].ch[1]].h==tree[tree[r].ch[0]].h+1)
  107. zag(r);
  108. else zigzag(r);
  109. }
  110. update(r);
  111. }
  112. int del(int &r,int x)
  113. {
  114. int temp;
  115. if(tree[r].val==x||(tree[r].val<x&&tree[r].ch[1]==0)||(tree[r].val>x&&tree[r].ch[0]==0))
  116. {
  117. if(tree[r].ch[1]==0||tree[r].ch[0]==0)
  118. {
  119. temp=tree[r].val;
  120. r=tree[r].ch[1]+tree[r].ch[0];
  121. return temp;
  122. }
  123. else
  124. {
  125. temp=tree[r].val; //注意这里,这样保证待删除节点只删掉了一个。
  126. tree[r].val=del(tree[r].ch[0],x);
  127. }
  128. }
  129. else if(tree[r].val<x)
  130. temp= del(tree[r].ch[1],x);
  131. else temp=del(tree[r].ch[0],x);
  132. maintain(r);
  133. return temp;
  134. }
  135. int query(int r,int rk)//鎵炬帓鍚嶄负绗瑀k鐨勫厓绱?
  136. {
  137. if(r==0)return 0;
  138. int t=tree[r].ch[0];
  139. if(tree[t].sz>=rk)
  140. return query(tree[r].ch[0],rk);
  141. else if(tree[t].sz+1<rk)
  142. return query(tree[r].ch[1],rk-tree[t].sz-1);
  143. else return tree[r].val;
  144. }
  145. int main()
  146. {
  147. int t,u,rnk=0;
  148. scanf("%d%d",&n,&m);
  149. for(int i=0;i<n;i++)
  150. {
  151. scanf("%d",&t);
  152. insert(root,t);
  153. }
  154. rnk=n;
  155. for(int i=0;i<m;i++)
  156. {
  157. scanf("%s",opt);
  158. if(opt[0]=='I')
  159. {
  160. rnk++;
  161. scanf("%d",&t);
  162. insert(root,t);
  163. }
  164. else if(opt[0]=='D')
  165. {
  166. scanf("%d",&t);
  167. if(find(root,t))
  168. {
  169. del(root,t);
  170. rnk--;
  171. }
  172. }
  173. else if(opt[0]=='M')
  174. {
  175. scanf("%d%d",&t,&u);
  176. if(find(root,t))
  177. {
  178. del(root,t);
  179. insert(root,u);
  180. }
  181. }
  182. else if(opt[0]=='Q')
  183. {
  184. printf("%d\n",query(root,(rnk+1)/2));
  185. }
  186. }
  187. return 0;
  188. }

  

AVL的删除写法的一个错误的更多相关文章

  1. 关于Java中的继承和组合的一个错误使用的例子

    [TOC] 关于Java中的继承和组合的一个错误使用的例子 相信绝大多数人都比较熟悉Java中的「继承」和「组合」这两个东西,本篇文章就主要就这两个话题谈论一下.如果我某些地方写的不对,或者比较幼稚, ...

  2. Vim安装jedi-vim提示的一个错误

    (仅为了提醒自己) 第一次的安装方法好像是通过 bundle安装的,好像是通过这个安装的并不是最新的版本,然后删除了通过下面的方法,最重要的是要执行 git submodule update --in ...

  3. 双缓冲绘图和窗口控件的绘制——ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误 .

    双缓冲绘图和窗口控件的绘制 ---ATL ActiveX 窗口控件生成向导绘制代码OnDraw的一个错误 cheungmine 我们通常使用ATL COM组件,生成一个带窗口的ActiveX控件,然后 ...

  4. [20180904]工作中一个错误.txt

    [20180904]工作中一个错误.txt --//昨天看我提交一份修改建议,发现自己写的sql语句存在错误.--//链接:http://blog.itpub.net/267265/viewspace ...

  5. MySQL删除数据库时的错误(errno: 39)

    由于mysql数据库是默认区分大小写的,部署的时候发现多了一些重复的表,于是就把多余的表删掉了.可是,剩下的重复的表再删除时会提示:表不存在. 于是,想把数据库删掉重新创建,可是,得到了 ERROR ...

  6. makefile的一个错误:*** missing separator

    原文转自:http://blog.sina.com.cn/s/blog_87c063060101c9yp.html 1.在写 多目录下makefile的时候,碰到一个错误提示,让我纠结许久,后面还是解 ...

  7. RDP 协议组件 X.224 在协议流中发现一个错误并且中断了客户端连接

    如果你的服务器有如下错误: “RDP 协议组件 X.224 在协议流中发现一个错误并且中断了客户端连接.” 可能的有2种: 1:你试试能否能继续远程登陆,有可能你的远程登陆组件出现问题. 2:有人攻击 ...

  8. git 如何删除远程仓库的错误提交

    前言 最近一个版本发生产环境以后,忘了把分支切回开发分支,直接在release分支上开发新功能提交了....于是就需要去删除远程仓库的错误提交. git命令行实现 1.强制返回上次的版本(~1回退到上 ...

  9. C#反序列化XML异常:在 XML文档(0, 0)中有一个错误“缺少根元素”

    Q: 在反序列化 Xml 字符串为 Xml 对象时,抛出如下异常. 即在 XML文档(0, 0)中有一个错误:缺少根元素. A: 首先看下代码: StringBuilder sb = new Stri ...

随机推荐

  1. Java常用的输入输出方法

    对于经常上机刷题的来说,首先得解决输入输出方法,Java的输入输出流在Java学习过程的后面部分才会接触,但是我们可以掌握一些简单的,常用的输入输出方法 首先输出 大家最熟悉的莫过于输出方法,直接用S ...

  2. AI第二次作业

    2.9  设有如下语句,请用相应的谓词公式分别把它们表示出来: (1)有的人喜欢梅花,有的人喜欢菊花,有的人既喜欢梅花又喜欢菊花.      解:设 P(x): x是人      L(x,y): x喜 ...

  3. react native 之 react-native-image-picke的详细使用图解

    最近需要在react native项目中集成相机和相册的功能,于是在网上找了一个好用的第三方插件:react-native-image-picke. 该插件可以同时给iOS和Android两个平台下使 ...

  4. C# foreach,等量代换,冒泡排序

    foreach: foreach (int h in a) //可以将数组读出来(自动遍历数组)                {                    Console.WriteLi ...

  5. jquery 操作

    Jquery使用时要引用,引用时放在最前. Jquery: $代表选择器, $(document) ready(function(e){}):找到页面,页面加载完成后执行. JS选取元素操作内容操作属 ...

  6. span标签设置margin-top没有效果

    <span>是行内元素,span只有margin-left和margin-right才有效果.要想margin-top生效就要把span转给块级元素才行.在span的css中加入以下属性即 ...

  7. VIM-Sed常用的一些记录。。。逐渐学习。。

    :[range]co[py] {address} :t :[range]m[ove] {address] 例如 :1,3t10  1-3行复制到10行后.用m就是移动了. :sort / /   // ...

  8. php字符串处理函数大全

      addcslashes - 为字符串里面的部分字符添加反斜线转义字符addslashes - 用指定的方式对字符串里面的字符进行转义bin2hex - 将二进制数据转换成十六进制表示chop - ...

  9. MediaCodec Name & Type

    OMX.google.mp3.decoder support type:audio/mpegOMX.google.amrnb.decoder support type:audio/3gppOMX.go ...

  10. ueditor 上传的图片在内容里显示的尺寸过大的问题

    没改动之前是上面这样的,图片显示不开,撑出了滚动条,想让他自适应100%,不出现滚动条 网上有方法 1.ueditor 的 themes 文件夹下有个iframe.css 加入以下代码,保存(原先的c ...