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.所有记录都在叶子节点上, 并且是顺序存放,如果用户从最左边的叶子节点开始顺序遍历,可以得到所有简直的顺序 排 ...
随机推荐
- 关于在VS2008和VS2010中禁用及卸载Visual Assist X的方法研究——转载
禁用和启用 此方法对于VS2008和VS2010 都适用. 在VS2008或VS2010菜单栏中选择“VassistX”选项卡,找到“Enable/Disable Visual Assist X” ...
- socket编程的同步、异步与阻塞、非阻塞示例详解
socket编程的同步.异步与阻塞.非阻塞示例详解之一 分类: 架构设计与优化 简介图 1. 基本 Linux I/O 模型的简单矩阵 每个 I/O 模型都有自己的使用模式,它们对于特定的应用程序 ...
- 使用Python抓取猫眼近10万条评论并分析
<一出好戏>讲述人性,使用Python抓取猫眼近10万条评论并分析,一起揭秘“这出好戏”到底如何? 黄渤首次导演的电影<一出好戏>自8月10日在全国上映,至今已有10天,其主演 ...
- 新建gradle文件
按照新建自动步骤,建好文件后,在build-gradle 里面 写上: allprojects { group 'aaaa' version '1.0-SNAPSHOT' apply plugin: ...
- windows环境安装zabbix客户端
安装windows版zabbix客户端 一.下载客户端 在数据盘新建一个zabbix_agent目录 浏览器打开 https://www.zabbix.com/download_agents 选择”z ...
- Webpack Plugin
[Webpack Plugin] Since Loaders only execute transforms on a per-file basis, plugins are most commonl ...
- 数据类型&分支流程控制(2)
1.数据类型 1.数据类型 局部变量:书写在方法中的变量: 全局变量:书写在类中,与方法平级的变量: -如果没有给变量赋初值 -全局变量会默认拥有一个初始值 -局部变量将没有初始值,这个时候不能使用这 ...
- ORACLE grant权限
oracle的系统和对象权限 本文转自: http://hi.baidu.com/zhaojing_boy/blog/item/0ffe95091266d939e824885f.html alter ...
- 使用rsync 同步数据一些常用参数和示例
rsync rsync是linux系统下的数据镜像备份工具.支持远程同步,本地复制,或者与其他SSH.rsync主机同步. 包括本地推到远程,远程拉到本地两种同步方式,也可以实现本地不同路径下文件的同 ...
- python全栈 字符串,整数,bool 数据类型运用
python全栈 一.基本数据类型 1.int: 整数 2.str: 字符串, 一般不存放大量数据. 3.bool: 布尔值,用来判断. True 或者 False 4.list: 列表,用来存 ...