C++树的插入和遍历(关于指针的指针,指针的引用的思考)
题目
写一个树的插入和遍历的算法,插入时按照单词的字典顺序排序(左边放比它“小”的单词,右边放比它“大”的单词),对重复插入的单词进行计数。
程序源码
#include <iostream>
#include <cstring>
#include <sstream> //vs2010中不加入这句话不能使用cin和cout,用gcc编译不用加
using namespace std;
struct Tnode
{
string word;
int count;
Tnode *left;
Tnode *right;
};
//根据word分配一个新的Tnode存储,并返回其引用
Tnode* GenNewTnode(const string&);
//将word按顺序放入树中,如果已存在则对应count加一
//返回插入树中节点的指针
Tnode* InsertWordToTree(Tnode*&,const string&);
//根据左,中,右的顺序遍历数的所有节点
void ShowTree(Tnode*,bool,int = 2);
int main()
{
cout<<"输入各个单词,输入“结束”结束"<<endl;
Tnode* tree = 0;
while(1)
{
string word;
cin>>word;
if(word == "结束")
break;
InsertWordToTree(tree,word);
}
ShowTree(tree,true/*省略第三个参数*/);
}
//根据word分配一个新的Tnode存储,并返回其引用
Tnode* GenNewTnode(const string& word)
{
Tnode* tN = new Tnode;
tN->word = word;
tN->count = 1;
tN->left=(tN->right=0);
return tN;
}
//将word按顺序放入树中,如果已存在则对应count加一
//返回插入树中节点的指针
Tnode* InsertWordToTree(Tnode*& root,const string& word)
{
Tnode* tN = root;
if(root == 0) //空树
{
root = GenNewTnode(word); //产生第一个根节点
return root;
}
while (1)
{
int oder = word.compare(tN->word);
if(oder == 0) //单词存在
{
tN->count++;
return tN;
}
Tnode*& nextTN = (oder<0)?(tN->left):(tN->right); //迭代搜索
if(nextTN == 0)
{
nextTN = GenNewTnode(word); //没找到,产生新的节点
return tN;
}
tN = nextTN;
}
}
//根据左,中,右的顺序遍历数的所有节点
//indent:是否需要输出空格
//spaces:节点之间插入多少空格
void ShowTree(Tnode* root,bool indent,int spaces)
{
if(root)
{
ShowTree(root->left,indent,spaces+2);
if(indent)
{
for(int i = 0;i < spaces;i++)
cout<<" ";
}
cout<<root->word<<"("<<root->count<<")"<<endl;
ShowTree(root->right,indent,spaces+2);
}
}
思路解析,问题总结和思考
整体思路是分别需要实现三个函数:分配新的节点存储空间、将单词放入节点、显示树。
分配新的节点空间:根据给定的单词将其放入存储中,返回存储的指针即可。
显示树:二叉树的遍历是计算机二级考试的常客,比较简单。这里采用左->中->右的递归搜索算法(中序遍历LDR)。
Ps:补充一点计算机二级知识,中->左->右为前序遍历(DLR),左->中->右为中序遍历(LDR),左->右->中为后序遍历(LRD)。已知前序和后序遍历不能唯一的确定这颗二叉树。但已知前中或后中遍历都可以唯一确定二叉树。
将单词放入节点:这个函数中使用到了指针的引用,以前没有使用过指针的引用,在犯了一些错误之后才对指针的引用才有所体会。犯了两个低级的错误:
- 定义了一个局部指针变量指向需要添加节点的位置,然后使用GenNewTnode()分配存储空间。由于局部变量在返回的时候会释放掉所以并不会产生新的节点,需要使用指针的引用指向需要添加节点的位置(上面代码中的nextTN)。
- 为了简化程序想将局部变量tN定义为指针引用进行迭代,但是忽略了引用类型一旦在初始化时给出了定义就不能再指向其他位置了,这一点和指针不一样。
其实将指针看成普通的变量之后,再去理解指针的引用就容易许多了。
注意不能给局部指针分配存储,因为返回时指针就会释放。但是可以给加去引运算的指针的指针分配空间(*tN=new
,tN为指针的指针)。所以上面的InsertWordToTree函数可以使用指针的指针进行改写。
Tnode* InsertWordToTree(Tnode*& root,const string& word)
{
Tnode** tN = &root;
if(root == 0) //空树
{
root = GenNewTnode(word); //产生第一个根节点
return root;
}
while (1)
{
int oder = word.compare((*tN)->word);
if(oder == 0) //单词存在
{
(*tN)->count++;
return *tN;
}
tN = (oder<0)?(&((*tN)->left)):(&((*tN)->right)); //迭代搜索
if(*tN == 0)
{
*tN = GenNewTnode(word); //没找到,产生新的节点
return *tN;
}
}
}
注意tN = (oder<0)?(&((*tN)->left)):(&((*tN)->right)); //迭代搜索
和*tN = GenNewTnode(word); //没找到,产生新的节点
这两句话的表达,要取左右两边节点地址的地址给tN,这样才能保证分配空间的首地址放到了左右指针中。
当然我们也可以即不使用指针的引用也不使用指针的指针,使用普通的指针也能完成上面任务但是代码要稍微复杂一些,如下:
Tnode* InsertWordToTree(Tnode*& root,const string& word)
{
Tnode* tN = root;
if(root == 0) //空树
{
root = GenNewTnode(word); //产生第一个根节点
return root;
}
while (1)
{
int oder = word.compare(tN->word);
if(oder == 0) //单词存在
{
tN->count++;
return tN;
}
Tnode* temp = (oder<0)?(tN->left):(tN->right); //迭代搜索
if(temp == 0)
{
if(oder<0)
{
tN->left = GenNewTnode(word); //没找到,产生新的节点
return tN->left;
}
else
{
tN->right = GenNewTnode(word);
return tN->right;
}
}
tN = temp;
}
}
注意上面的temp变量虽然和tN->left都指向同一个地址,但是由于没使用引用,这两个指针的地址并不相同。不能给temp分配空间,而是给tN->left分配空间,即tN->left指向分配空间的首地址。
ps:虽然叙述起来比较啰嗦,但其实搞明白后指针的指针,指针的引用没有那么难,可能是我表达能力有限吧┑( ̄Д  ̄)┍。
C++树的插入和遍历(关于指针的指针,指针的引用的思考)的更多相关文章
- 萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)
萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...
- C++里创建 Trie字典树(中文词典)(一)(插入、遍历)
萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...
- 数据结构系列之2-3-4树的插入、查找、删除和遍历完整版源代码实现与分析(dart语言实现)
本文属于原创,转载请注明来源. 在上一篇博文中,详细介绍了2-3树的操作(具体地址:https://www.cnblogs.com/outerspace/p/10861488.html),那么对于更多 ...
- 数据结构系列之2-3树的插入、查找、删除和遍历完整版代码实现(dart语言实现)
弄懂了二叉树以后,再来看2-3树.网上.书上看了一堆文章和讲解,大部分是概念,很少有代码实现,尤其是删除操作的代码实现.当然,因为2-3树的特性,插入和删除都是比较复杂的,因此经过思考,独创了删除时分 ...
- B+树的插入、删除(附源代码)
B+ Tree Index B+树的插入 B+树的删除 完整测试代码 Basic B+树和B树类似(有关B树:http://www.cnblogs.com/YuNanlong/p/6354029.ht ...
- B树和B+树的插入、删除图文详解
简介:本文主要介绍了B树和B+树的插入.删除操作.写这篇博客的目的是发现没有相关博客以举例的方式详细介绍B+树的相关操作,由于自身对某些细节也感到很迷惑,通过查阅相关资料,对B+树的操作有所顿悟,写下 ...
- B树和B+树的插入、删除图文详解(good)
B树和B+树的插入.删除图文详解 1. B树 1. B树的定义 B树也称B-树,它是一颗多路平衡查找树.我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母m表示阶数 ...
- java:数据结构(四)二叉查找树以及树的三种遍历
@TOC 二叉树模型 二叉树是树的一种应用,一个节点可以有两个孩子:左孩子,右孩子,并且除了根节点以外每个节点都有一个父节点.当然这种简单的二叉树不能解决让树保持平衡状态,例如你一直往树的左边添加元素 ...
- MySQL B+树 的插入与删除
一.MySQL Index 的插入 有如下B+树,其高度为2,每页可存放4条记录,扇出为5.所有记录都在叶子节点上, 并且是顺序存放,如果用户从最左边的叶子节点开始顺序遍历,可以得到所有简直的顺序 排 ...
随机推荐
- 100个常用的Linux命令——转载
1,echo “aa” > test.txt 和 echo “bb” >> test.txt //>将原文件清空,并且内容写入到文件中,>>将内容放到文件的尾部 2 ...
- idea git 从github上拉取项目 更改上传
更改上传: 新增文件上传时注意:
- 吴裕雄 09-MySQL删除数据表
以下为删除MySQL数据表的通用语法:DROP TABLE table_name; DROP TABLE runoob_tbl; 使用PHP脚本删除数据表PHP使用 mysqli_query 函数来删 ...
- Java 中 == 和 equals 的区别
有一段时间,== 和 equals 的区别一直困扰着我.因为涉及到Java的内存机制,然而Java的内存机制又是比较抽象的东西,所以对那时候的我来说,实在是很难理解. == 和 equals 最大的区 ...
- Docker 指定容量
vim /etc/sysconfig/docker-storage加入以下命令 DOCKER_STORAGE_OPTIONS="--storage-driver devicemapper - ...
- 学JS的心路历程-物件与原型(一)
前两天说明面向对象的三大特性及JS不符合面向对象,只能称作支持面向对象而已,今天我们来看看JS的原型继承. 首先我们先来看,什么是原型(vmwork): 两个物件之间的原型关系(prototype r ...
- 初始C语言中的数组(男神翁凯老师MOOC)
定义数组 ●<类型>变量名称[元素数量]; ● int grades[100]; ●double weight[20]; ●元素数量必须是整数 ●C99之前:元素数量必须是编译时刻确定的字 ...
- HTML css 样式表
CSS样式表 2.1.样式表的基本概念 2.1.1.样式表分类 1.内联样式表 和html联合显示,控制精确,但是可重用性差,冗余多. 例:<p style="font-size:14 ...
- get请求中url传参中文乱码问题--集锦
一:get请求url中带有中文参数,有三种方式进行处理防止中文乱码 1.如果使用tomcat作为服务器,那么修改tomcat配置文件conf/server.xml中,在 <Connector ...
- editplus设置自动换行方法 editplus自动换行设置步骤
原文链接:https://www.jb51.net/softjc/165897.html 发布时间:2014-05-14 17:03:54 作者:佚名 我要评论 editplus自动换行设置 ...