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

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. 分布式文件系统 - FastDFS 配置 Nginx 模块及上传测试

    也不说废话,直接干 上一篇 分布式文件系统 - FastDFS 在 CentOS 下配置安装部署 中安装了 FastDFS 后,并配置启动了 Tracker 和 Storage 服务,已经可以上传文件 ...

  2. VMware安装CentOS时,无法以图形界面安装解决办法

    有的同学问: 用虚拟机软件(vmware.VirtualBox)安装CentOS系统时, 安装过程中没有中文,也没有出现图形界面,都是以命令行方式去安装, 有时候又会出现图形界面,不知道哪里配置的问题 ...

  3. Nginx配置文件nginx.conf中文详解(转)

    ######Nginx配置文件nginx.conf中文详解##### #定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数. worker_ ...

  4. 解决springmvc+mybatis+mysql中文乱码问题【转】

    这篇文章主要介绍了解决java中springmvc+mybatis+mysql中文乱码问题的相关资料,需要的朋友可以参考下 近日使用ajax请求springmvc后台查询mysql数据库,页面显示中文 ...

  5. div 模拟<select>事件

    IE7 下,不能够自定义<select>/<option>的样式,所以为了方便起见,用div可以进行模拟 <!doctype html> <html> ...

  6. Web性能优化:基本思路和常用工具

    听了荣华的演讲之后,我对性能优化有了更深层次的认识. 性能优化的重要性 性能优化是为了赢得用户,为了降低成本. 性能优化思路 Web常见优化点   Java常见排查工具  

  7. 一个基于Microsoft Azure、ASP.NET Core和Docker的博客系统

    2008年11月,我在博客园开通了个人帐号,并在博客园发表了自己的第一篇博客.当然,我写博客也不是从2008年才开始的,在更早时候,也在CSDN和系统分析员协会(之后名为“希赛网”)个人空间发布过一些 ...

  8. OpenSceneGraph 编译 error LNK2019:unresolved external symbol 错误

    在编译 OpenSceneGraph 的一个简单示例时, #include <osgViewer/Viewer> #include <osgDB/ReadFile> void ...

  9. Eclipse中JAR System library 没有怎么添加?

    1.打开  >>  Eclipse 2.右击项目   >>  Build path  >>  Configure Build path  如图1: 图1 3.进入 ...

  10. monkey命令选项参考

    基本参数:     --help              打印帮助消息 -v  可以在命令行中出现多次,每次一个-V选项都会增加monkey向命令行打印输出的详细级别.默认的级别0只会打印启动信息. ...