二叉树算法引发的指针参数传递和引用的思考
来源:互联网 发布:淘宝怎么修改评价 编辑:程序博客网 时间:2024/06/05 10:44
最近想熟悉一下基本的数据结构和算法,于是写了一个二叉树程序,功能很简单,只有二叉树的建立和遍历。在这个过程中,却发现了一些平时没有注意到的细节问题,写出来作为总结和大家分享。
待讨论和遇到的细节问题如下:
(1)常见的定式思维:指针作为参数传递,是否就不需要再赋值,因为指针指向的值会同步更改,但是,你有考虑过,如果指针变量本身的值被更改了呢?怎么办?
(2)比较不常用的用法,针对指针变量的引用,你用过吗?
前提:
(1)笔者考虑到自己一直混淆使用C和C++,于是,打算这个简单的算法程序采用纯C来写,因此使用的是C编译器。
(2)关于C和C++的一些区别,笔者打算另外写一些系列文章来总结分析。
(3)另外,因为是练习写的程序,暂时还没有添加内存释放的方法。
程序的头部定义以及通用的方法:
#include <stdio.h>#include <malloc.h>#define TRUE 1#define FALSE -1typedef char ElemType; typedef int BOOL;typedef struct _BinaryTreeNode{ElemType elem;struct _BinaryTreeNode* left;struct _BinaryTreeNode* right;}BinareTreeNode, *BiTree;void PrintNode(ElemType elem){printf("%c ", elem);}void PreOrderTraverse(BinareTreeNode* pNode, void(* Visit)(ElemType elem)){if (NULL != pNode){Visit(pNode->elem);PreOrderTraverse(pNode->left, PrintNode);PreOrderTraverse(pNode->right, PrintNode);}}
笔者最初写的程序如下:
void PreOrderCreateBinaryTree(BinareTreeNode* pNode){ElemType elem;scanf("%c", &elem);if ('#' == elem){pNode = NULL;}else{pNode = (BinareTreeNode*)malloc(sizeof(BinareTreeNode));pNode->elem = elem;PreOrderCreateBinaryTree(pNode->left);PreOrderCreateBinaryTree(pNode->right);}}int main(){BinareTreeNode* pHeadNode = NULL;PreOrderCreateBinaryTree(pHeadNode);PreOrderTraverse(pHeadNode, PrintNode);return 0;}
你能看出来问题在哪里吗?先思考,不要急着往后看。
具体问题现象:
原本以为这样写是没有问题的,实际上,main函数中的pHeadNode的值一直都是NULL,导致PreOrderTraverse时没有任何值输出。
输入:ABD##E##C## 遍历后输出:无,原因是传入的参数值pHeadNode为NULL。
具体问题分析:
为什么会这样呢?
本文讨论的第一个问题浮出水面:常见的定式思维:指针作为参数传递,是否就不需要再赋值?
分析:
虽然是指针传递,main函数中的pHeadNode,是一个指针变量,指针变量的值为空,不存在指向的值。
PreOrderCreateBinaryTree函数中的形参pNode却是另一个指针变量,刚开始的时候其值由main函数中传入,也是NULL,后来pNode经过malloc被重新赋值。
问题是,main函数中的pHeadNode有没有被同步改变呢?不是说指针传递,值会一起改变吗?
其实,这里犯了一个低级错误,就是说使用指针作为函数的参数,指针没有被重新赋值的情况下,指针指向的值一定是会被同步更改的,但是如果指针作为一个变量,本身的值发生更改,那么参数源是不会发生改变的。
举个例子:
(1)指针指向的值会被同步更改void FuncChangeObj(int* pInt){(*pInt)++;}(2)指针本身的变量值被更改,此后,此函数内的指针与源指针将指向不同的值,也不会发生同步更改void FuncNoChangeObj(int* pInt){pInt = (int*)malloc(sizeof(int));*pInt = 10;}
上例二叉树程序先序遍历不成功,就是因为先序创建二叉树的时候,并没有将二叉树的根节点返回,导致pHeadNode一直为NULL。
那么,是不是说,上述程序其实创建二叉树成功,只是没有返回树的根节点呢?不然,因为也是同样的原因,导致这个二叉树并没有创建成功,各个树节点之间并无关联,全是孤立的节点。
具体问题解决之道:
如何修改呢?
给出答案如下:
方法一:函数返回指针,对源指针进行赋值
BinareTreeNode* PreOrderCreateBinaryTree(BinareTreeNode* pNode){ElemType elem;scanf("%c", &elem);if ('#' == elem){pNode = NULL;}else{pNode = (BinareTreeNode*)malloc(sizeof(BinareTreeNode));pNode->elem = elem;pNode->left = PreOrderCreateBinaryTree(pNode->left);pNode->right = PreOrderCreateBinaryTree(pNode->right);}return pNode;}int main(){BinareTreeNode* pHeadNode = NULL;pHeadNode = PreOrderCreateBinaryTree(pHeadNode);PreOrderTraverse(pHeadNode, PrintNode);return 0;}
方法二:使用指针的引用进行传值,即对指针变量本身进行引用,而不是指针变量值传递
注:本方法即是对第二个问题的阐释,但是要要注意,此方法在C语言编译器中是无法编译成功过的,因为C语言中并不存在引用的概念。
void PreOrderCreateBiTree2(BiTree& T){ElemType elem;scanf("%c", &elem);if ('#' == elem){T = NULL;}else{T = (BinareTreeNode *)malloc(sizeof(BinareTreeNode));T->elem = elem;PreOrderCreateBiTree2(T->left);PreOrderCreateBiTree2(T->right);}}int main(){BiTree T = NULL;PreOrderCreateBiTree2(T);PreOrderTraverse(T, PrintNode);return 0;}
- 二叉树算法引发的指针参数传递和引用的思考
- 二叉树算法引发的思考:指针参数传递、引用的陷阱
- (转)二叉树算法引发的思考:指针参数传递、引用的陷阱
- 由JAVA参数传递引发的对引用的思考
- 笔试题引发的思考--引用传递
- 指针和引用的参数传递
- 参数的值传递,指针传递和引用传递
- 验证JavaScript函数“按参数传递”特性引发的思考
- C++之函数参数的值传递、指针传递以及引用传递的区别和联系
- C++ 参数指针传递、引用传递、值传递的区别
- 引用和指针 传递参数
- 指针型形参和指针引用的传递
- C++ 函数参数传递-传递指向指针的引用
- 关于指针和引用的思考
- c++中指针和引用的思考
- 值传递-引用传递-指针传递-函数调用时指针参数的传递
- 关于指针传递和指针的引用传递
- 用函数指针代替C++的引用参数 参数传递
- 在windows下编译webrtc代码库 ninja编译
- Linux
- android项目中,测试Socket连接时遇到的问题
- CSS3过渡
- getopts详解
- 二叉树算法引发的指针参数传递和引用的思考
- The method getJspApplicationContext(ServletContext) is undefined for the type JspFactory的解决方法
- 使用PowerDesigner画ER图详细教程
- linux之vim命令使用
- 最牛x的滚动插件 – jquery的iscroll插件(附上下拉刷新消息demo)
- 1001. 害死人不偿命的(3n+1)猜想 (15)
- C/Linux C编码笔记
- 初学Struts 2创建一个Hello World例子(注解版)
- LeetCode 73. Set Matrix Zeroes