关于树的学习该一段落,在这里就简单的总结一下自己曾经踩过的坑,希望能给看到这篇文章、正在学习树的朋友带来学习的灵感。
- 首先想要学习树,必须完全掌握它的物理概念,多看几遍都不为过,学树最重要的是有层次感,自己在脑子中幻想一棵苹果树,数据就是上面的苹果。
- 就下来就是遍历问题,这个地方曾经困扰我很久(看不懂前序,中序,后序是怎样便利的),虽然你看着例题在脑子中走了一遍,但是自己真的已经懂了吗?给你个新的可以给出答案吗?
给个例子:
正确的遍历是:
1)前序:A B D E H I F C G
大家都知道前序遍历就是从根开始,这个规则不仅仅适用于第一个节点(A),它适用于所有的节点,A下面是B,B下面是D,在这里是因为D没有孩子了,不然首先访问的还是D的左右孩子。然后自左向右进行访问,碰到了E,但是E是有孩子的,好了上面说的规则也适用E,首先会访问它的孩子,知道碰到叶子才会结束,开始访问F,接着访问右树,在右子树中对于每个节点也是按照那个规则再遍历,注意是每个节点!!!
2)后序:D H I E F B G C A
后序就是最后访问根,它一开始就是使劲查左子树,直到D因为到这就是叶子了所以停止,开始从这层从左到右进行访问,碰到E,但是E是有孩子的,既然有就必须访问完它的孩子(孙子)也是查左子树直到叶子,最后访问完再访问根节点。
3)中序是对于二叉树而言的,我给的这个例子并不适用,道理还是那样,对于每个节点都是先访问左子树,再访问根,最后访问右子树。
4)层序遍历是我认为最麻烦的(代码实现),我还没有试过,也不清楚。(靠大家自学成才了)
下面给出各种便利的递归代码(虽然有非递归的,但是我还是推荐递归算法,原因很简单,简单易懂,还容易写,代码量小)
——————————————————————————————————————————————————————————————————————————
前序:(分别给出顺序存储和链式存储的遍历代码)
void Preorder(int root, char data[]){
if(data[root]!='\0'){
cout<<data[root] ;
Preorder(2*root,data);
Preorder(2*root+1,data);
}
return;
}
void Tree::before(Node *root)
{
if(root==nullptr)
{
return;
}
else
{
cout<<root->data;
before(root->lchild);
before(root->rchild);
}
}
——————————————————————————————————————————————————————————————————————————
中序:(分别给出顺序存储和链式存储的遍历代码)
void InOrder(int root, char data[]){
if(data[root]!='\0'){
InOrder(2*root,data);
cout<<data[root] ;
InOrder(2*root+1,data);
}
return;
}
void Tree::Inorder(Node *root)
{
if(root==nullptr)
{
return;
}
else
{
Inorder(root->lchild);
cout<<root->data;
Inorder(root->rchild);
}
————————————————————————————————————————————————————————————————————————————————————
后序:(分别给出顺序存储和链式存储的遍历代码)
void PostOrder(int root, char data[]){
if(data[root]!='\0'){
PostOrder(2*root,data);
PostOrder(2*root+1,data);
cout<<data[root] ;
}
return;
}
void Tree::last(Node *root)
{
if(root==nullptr)
{
return;
}
else
{
last(root->lchild);
last(root->rchild);
cout<<root->data;
}
}
后面还有哈夫曼最优二叉树什么的,都是算法了,这里就不再累述。看懂就好了。