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

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. Hibernate入门详解

    学习Hibernate ,我们首先要知道为什么要学习它?它有什么好处?也就是我们为什么要学习框架技术? 还要知道    什么是Hibernate?    为什么要使用Hibernate?    Hib ...

  2. php-fpm优化

    pid = run/php-fpm.pid #pid设置,默认在安装目录中的var/run/php-fpm.pid,建议开启 error_log = log/php-fpm.log #错误日志,默认在 ...

  3. jQuery获取短信验证码+倒计时实现

    jQuery 短信验证码倒计时 <script type="text/javascript" charset="utf-8"> $(function ...

  4. Microsoft Dynamics CRM 解决数据大于5000时,页面上只能导出5000+数据。

    页面显示: update [MSCRM_CONFIG].[dbo].[DeploymentProperties] set IntColumn=10000 --调整成10000+   页面导出: 一.在 ...

  5. MVP解析

    一套可以直接复制使用的MVP框架 通过对MVP设计模式学习,对MVP也有了一个初步的认识,以登录Login模块为例,封装MVP如下: package com.example.administrator ...

  6. c#批量插入数据库Demo

    using System; using System.Collections.Generic; using System.Configuration; using System.Data; using ...

  7. Oracle发送邮件,支持HTML,多收件人,多附件

    Oracle发邮件,权限问题 - 创建 ACL BEGIN DBMS_NETWORK_ACL_ADMIN.CREATE_ACL(acl => 'email_server_permissions. ...

  8. ASP.NET MVC Routing、Areas、URLs

    webForm页面运行起来url一般是这样的:localhost:****/index.aspx,这个过程就是当你运行页面的时候,vs开发工具自带的微型服务器会打开你存在硬盘上的这个文件然后显示在浏览 ...

  9. kd树和knn算法的c语言实现

    基于kd树的knn的实现原理可以参考文末的链接,都是一些好文章. 这里参考了别人的代码.用c语言写的包括kd树的构建与查找k近邻的程序. code: #include<stdio.h> # ...

  10. python list dict 去重的两种方式

    def dedupe(items, key=None): seen = set() for item in items: val = item if key is None else key(item ...