题目

写一个树的插入和遍历的算法,插入时按照单词的字典顺序排序(左边放比它“小”的单词,右边放比它“大”的单词),对重复插入的单词进行计数。

程序源码


#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)。已知前序和后序遍历不能唯一的确定这颗二叉树。但已知前中或后中遍历都可以唯一确定二叉树。

将单词放入节点:这个函数中使用到了指针的引用,以前没有使用过指针的引用,在犯了一些错误之后才对指针的引用才有所体会。犯了两个低级的错误:

  1. 定义了一个局部指针变量指向需要添加节点的位置,然后使用GenNewTnode()分配存储空间。由于局部变量在返回的时候会释放掉所以并不会产生新的节点,需要使用指针的引用指向需要添加节点的位置(上面代码中的nextTN)。
  2. 为了简化程序想将局部变量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++树的插入和遍历(关于指针的指针,指针的引用的思考)的更多相关文章

  1. 萌新笔记——C++里创建 Trie字典树(中文词典)(一)(插入、遍历)

    萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...

  2. C++里创建 Trie字典树(中文词典)(一)(插入、遍历)

    萌新做词典第一篇,做得不好,还请指正,谢谢大佬! 写了一个词典,用到了Trie字典树. 写这个词典的目的,一个是为了压缩一些数据,另一个是为了尝试搜索提示,就像在谷歌搜索的时候,打出某个关键字,会提示 ...

  3. 数据结构系列之2-3-4树的插入、查找、删除和遍历完整版源代码实现与分析(dart语言实现)

    本文属于原创,转载请注明来源. 在上一篇博文中,详细介绍了2-3树的操作(具体地址:https://www.cnblogs.com/outerspace/p/10861488.html),那么对于更多 ...

  4. 数据结构系列之2-3树的插入、查找、删除和遍历完整版代码实现(dart语言实现)

    弄懂了二叉树以后,再来看2-3树.网上.书上看了一堆文章和讲解,大部分是概念,很少有代码实现,尤其是删除操作的代码实现.当然,因为2-3树的特性,插入和删除都是比较复杂的,因此经过思考,独创了删除时分 ...

  5. B+树的插入、删除(附源代码)

    B+ Tree Index B+树的插入 B+树的删除 完整测试代码 Basic B+树和B树类似(有关B树:http://www.cnblogs.com/YuNanlong/p/6354029.ht ...

  6. B树和B+树的插入、删除图文详解

    简介:本文主要介绍了B树和B+树的插入.删除操作.写这篇博客的目的是发现没有相关博客以举例的方式详细介绍B+树的相关操作,由于自身对某些细节也感到很迷惑,通过查阅相关资料,对B+树的操作有所顿悟,写下 ...

  7. B树和B+树的插入、删除图文详解(good)

    B树和B+树的插入.删除图文详解 1. B树 1. B树的定义 B树也称B-树,它是一颗多路平衡查找树.我们描述一颗B树时需要指定它的阶数,阶数表示了一个结点最多有多少个孩子结点,一般用字母m表示阶数 ...

  8. java:数据结构(四)二叉查找树以及树的三种遍历

    @TOC 二叉树模型 二叉树是树的一种应用,一个节点可以有两个孩子:左孩子,右孩子,并且除了根节点以外每个节点都有一个父节点.当然这种简单的二叉树不能解决让树保持平衡状态,例如你一直往树的左边添加元素 ...

  9. MySQL B+树 的插入与删除

    一.MySQL Index 的插入 有如下B+树,其高度为2,每页可存放4条记录,扇出为5.所有记录都在叶子节点上, 并且是顺序存放,如果用户从最左边的叶子节点开始顺序遍历,可以得到所有简直的顺序 排 ...

随机推荐

  1. kibana test

    https://www.cnblogs.com/yiwangzhibujian/p/7137546.html curl -XPUT http://localhost:9200/shakespeare ...

  2. opencv 对RGB图像直接二值化

    #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace st ...

  3. nbtscan工具

    这是一款用于扫描Windows网络上NetBIOS名字信息的程序.该程序对给出范围内的每一个地址发送NetBIOS状态查询,并且以易读的表格列出接收到的信息,对于每个响应的主机,NBTScan列出它的 ...

  4. target=_blank攻击

    [target=_blank攻击] 在<a>标签中加入 rel="noopener noreferrer" 来避免. 参考:https://mathiasbynens. ...

  5. java定义object数组(可以存储String或int等多种类型)

    需求| 想在数组中既有String类型又有int等类型,所以需要定义数组为Object类型   背景| 现在有一个字符串params,需要对其进行逗号分隔赋值到数组里,这时遇到了个问题,即使直接定义的 ...

  6. python+selenium的环境配置

    以前写过关于python和selenium加myeclipse的环境配置,但是myeclipse启动时过于费时,虽然myeclipse有很好的提示功能,但是作为初学者,我还是直接用python的idl ...

  7. Python爬虫使用MD5加密的坑

    由于公司的业务需要,需要爬取很多的国外网站图片,然后兄弟我一路正则杀过去,总共匹配到658张链接,心里美滋滋开始写下载的代码.然后就有了这次坑的记录. 首先这是我查到的链接数量 然后爬虫跑完后,美滋滋 ...

  8. c++中的类(class)-----笔记(类多态)

    1,多态是一种运行期绑定机制,通过这种机制,实现将函数名绑定到函数具体实现代码的目的.一个函数的名称与其入口地址是紧密相连的,入口地址是该函数在内存中的起始地址.如果对一个函数的绑定发生在运行时刻而非 ...

  9. elasticsearch 不同集群数据同步

    采用快照方式 1.源集群采用NFS,注意权限 2.共享目录完成后,在所有ES服务器上挂载为同一目录 3.创建快照仓库 put _snapshot/my_backup{ "type" ...

  10. mysql windows安装资源

    压缩包资源 https://mirrors.tuna.tsinghua.edu.cn/mysql/downloads/MySQL-5.7/ 配置流程 https://blog.csdn.net/hel ...