zoukankan      html  css  js  c++  java
  • [速记]关于指针,引用和递归和解递归——C++

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

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

  • 相关阅读:
    react 封装antd menu组件,路由懒加载,可折叠,可配置显示和隐藏,刷新后选择正确的菜单,打开正确的submenu
    useHistory做页面跳转导航
    react-draft-wysiwyg富文本组件
    html转json json转html
    create-react-app 生成 report.html 可视化打包分析
    axios设置请求头实现post请求发送数据的格式(Form Data)
    url查询参数中的汉字如何解码
    React在body下追加全局组件并实现渲染更新
    Loadrunner-08-增强和优化脚本-检查点
    Loadrunner-06-增强和优化脚本-事务
  • 原文地址:https://www.cnblogs.com/YTYMblog/p/6130846.html
Copyright © 2011-2022 走看看