在写基于二叉排序树的查找时,分为三个过程

1.二叉排序树的插入

2.二叉排序树的建立

3.基于二叉排序树的查找

其中第三部可以递归方式实现,也可以用while循环解递归,于是我想也解解第一步的递归,看看行不行,结果给了我当头一棒,解递归失败!

最后我分析了一下原因:

首先看一下,原来递归的实现方式

typedef struct  _TreeNode
{
struct _TreeNode *leftNode;
struct _TreeNode *rightNode;
TypeData data;
}TreeNode,*TreeRoot;
//返回插入位置的结点
TreeNode* Insert_Tree(TreeRoot &root,TypeData key)
{
if (!root)
{
TreeNode *node=new TreeNode;
node->data=key;
node->leftNode=nullptr;
node->rightNode=nullptr;
root=node;
return root;
}
else if (root->data==key)
{
return root;
}
else if (root->data<key)
{
return (Insert_Tree(root->rightNode,key));
}
else if (root->data>key)
{
return(Insert_Tree(root->leftNode,key));
} }

  

然后,我自己实现了一下解递归的实现

//这个方法是错误的
TreeNode* Insert_Tree2(TreeRoot &root,TypeData key)
{
TreeNode *p=root;
while (p)
{
if (p->data==key)
{
return p;
break;
}
else if (p->data>key)
{
p=p->leftNode;
}
else
{
p=p->rightNode;
}
}
if (!p)
{
p=new TreeNode;
p->data=key;
p->leftNode=nullptr;
p->rightNode=nullptr;
return p;
} }

  

看似,没有什么问题,实际上却犯了一个灰常严重的错误

我们可以看到,两种方式都是以引用的形式传入了根节点,为什么用引用?

  因为我们插入的时候肯定会造一个新结点,然后要把它接到原来的树体系当中,第一种递归的方式中,最后造结点的时候

TreeNode *node=new TreeNode;
node->data=key;
node->leftNode=nullptr;
node->rightNode=nullptr;
root=node;
return root; 可以看到,标黑的位置,这个时候root是以引用的方式传入的,这个事实上直接更改了原来树体系中的结点 而在,解递归的实现当中,虽然是以引用的方式传入的参数,但是我们用了一个指针局部变量来代替他,最后的时候
          p=new TreeNode;
p->data=key;
p->leftNode=nullptr;
p->rightNode=nullptr;
return p;
他是这样执行的,这里的p怎样得到的呢?
p=上一个p的left,
这样一种方式的后果是什么呢?
它改变了两个指针共同指向的内容,却无法改变另一个指针本身,是不是觉得无法理解? 不要紧,p是根据上一个父节点的left来赋值的,假设上一个父节点叫做f
那么,也就是
p=f->left;
这个时候p和f->left都为nullptr,
一直到这个时候,都没有问题
然后我们一个劲儿地去更改p的内容,
这个时候,没错,我们通过p更改了两者共同指向的内容,可是!
f->left一直都是nullptr
你改的再多,依然与我无关啊! 不理解的,再看一个程序
    Node *p=new Node;
p->left=nullptr;
p->right=nullptr;
Node *l=p->left;
Node *q=p->left;
q=new Node;
q->data='q';
q->left=q;
q->right=q;
std::cout<<l->data;
std::cout<<q->data;

  

最后,总结一下:

1.要注意!修改指针和修改指针共同指向的内容是两回事!

2.凡是用到链式存储,当要改变结点之间的关系,或者增加结点的时候,这个时候最好用对指针的引用(二级指针也行,不过不推荐)。

3.当第二种情况用到递归的时候,解递归一定要谨慎,最好不要解递归!

4.事实上,只要不更改涉及到更改指针本身,一般都不会出现这种问题!此时实际上就是涉及到了更改了指针本身,却没有对原来的内容更新

[速记]关于指针,引用和递归和解递归——C++的更多相关文章

  1. Reverse Linked List 递归非递归实现

    单链表反转--递归非递归实现 Java接口: ListNode reverseList(ListNode head) 非递归的实现 有2种,参考 头结点插入法 就地反转 递归的实现 1) Divide ...

  2. paip.指针 引用 c++ java的使用总结.

    paip.指针 引用  c++ java的使用总结. ///////////////一般一个变量包括下面的信息 a.地址(指针)  b.命名(引用,别名)   c.变量内容.. 指针是一个变量的地址, ...

  3. Delphi函数翻译成VC要注意句柄指针传递(传递Handle的时候,必须加上一个指针引用,才能消除编译错误)

    Delphi里做了魔法变化,每个变量名称本身就是指针,因为不怎么需要指针语法.我也不知道是不是因为这个原因引起的Delphi与VC对句柄的不同处理. 这是Delphi的强行关机函数,好用,调用方式:W ...

  4. Java基础知识强化之IO流笔记12:递归之递归解决问题的思想(图解)

    1. 使用递归计算5!的结果,递归思想的本质如下: 2. 下面就要使用代码实现这个递归: 递归实现分析: (1)做递归要写一个方法 (2)出口条件 (3)规律 代码实现如下: package com. ...

  5. 【数据结构】——搜索二叉树的插入,查找和删除(递归&非递归)

    一.搜索二叉树的插入,查找,删除 简单说说搜索二叉树概念: 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右 ...

  6. C语言学习笔记 (007) - 数组指针和通过指针引用数组元素的方法总结

    1.数组指针:即指向数组的指针 那么, 如何声明一个数组指针呢? ]; /*括号是必须写的,不然就是指针数组:10是数组的大小*/ 拓展:有指针类型元素的数组称为指针数组. 2.通过指针引用数组元素的 ...

  7. C++中的二级指针和指针引用函数传参

    在函数的使用过程中,我们都明白传值和传引用会使实参的值发生改变.那么能够通过传指针改变指针所指向的地址吗? 在解决这个问题之前,也许我们应该先了解指针非常容易混淆的三个属性: ①.指针变量地址(&am ...

  8. 引用、数组引用与指针引用、内联函数inline、四种类型转换运算符

    一.引用 (1).引用是给一个变量起别名 定义引用的一般格式:类型  &引用名 = 变量名: 例如:int a=1;  int  &b=a;// b是a的别名,因此a和b是同一个单元 ...

  9. C++ 指针引用

    //指针引用 #include<iostream> using namespace std; struct Teacher{ ]; int age; }; int InitA(Teache ...

随机推荐

  1. AOS – 另外一个独特的页面滚动动画库(CSS3)

    AOS 是一个用于在页面滚动的时候呈现元素动画的工具库,你可能会觉得它和 WOWJS 一样,的确他们效果是类似的.但是AOS是 CSS3 动画驱动的库,当你滚动页面的时候能让元素动起来,当页面滚回顶部 ...

  2. [转]ASP.NET应用程序生命周期趣谈(二)

    在上回书开始的时候我们提到博客园的IIS看了一眼我的请求后就直接交给ASP.NET去处理了,并且要求ASP.NET处理完之后返回HTML以供展示. 那么我们不仅要问: 1,    IIS肯定是没有眼睛 ...

  3. koala预编译工具的使用

    Koala是一个开源的预处理语言图形编译工具,目前已支持Less.Sass.Compass与CoffeeScript. 安装Koala 在Koala官网根据你的系统平台下载对应的版本.Linux系统要 ...

  4. Mac OS X中bogon的处理

    起因 最近写一个项目,之前在eclipse里的tomcat启动是没问题的,最近不知怎么了,启动的时候ehcache会报一个错误,说java.net.UnknownHostException: bogo ...

  5. Oracle学习笔记二 初识Oracle(二)

    Windows 中的 Oracle 服务 Oracle 9i的每个实例在Windows中都作为一项服务启动 服务是在 Windows 注册表中注册的可执行进程,由 Windows 操作系统管理 “服务 ...

  6. 如何在github上下载单个文件夹?

    作者:ce ge链接:https://www.zhihu.com/question/25369412/answer/96174755来源:知乎著作权归作者所有,转载请联系作者获得授权. Git1.7. ...

  7. python ldap

    # -*- coding: UTF-8 -*- import ldap, ConfigParser, os from ldap import modlist LDAP_HOST = "myd ...

  8. MDK st-link下载STM32程序出现Internal command error和Error:Flash download failed. Target DLL

    MDK st-link下载STM32程序出现Internal command error和Error:Flash download failed. Target DLL   是因为目标板的芯片处于休眠 ...

  9. 【python之路1】python安装与环境变量配置

    直接搜索 Python,进入官网,找到下载,根据个人电脑操作系统下载相应的软件.小编的是windows os .下载python-2.7.9.msi 安装包  双击安装程序,进入安装步骤.在安装过程中 ...

  10. 第9章 Shell基础(3)_Bash的变量

    4. Bash的变量 4.1 用户自定义变量 4.1.1 什么是变量 变量是计算机的内存单元,其中存放的值可以改变.当Shell脚本需要保存一些信息时,如一个文件名或是一个数字,就把它存放在一个变量中 ...