本周学了二叉树,感觉还挺好玩的hhh
写作业的时候建立二叉树有点问题,其他思路都还可以
据说学好二叉树就是学好递归,感觉自己递归不是特别好😭
数据结构的期中考要到啦,好好复习~
有一题画二叉树结构的,一开始有点晕,但今天又画了一次,还不错。
根据广义表建立二叉树
广义表的表名放在表前,表示树的根结点,括号中是根的左、右子树。每个结点的左、右子树用逗号隔开。若仅有右子树没有左子树,逗号不能省略。在整个广义表表示输入的结尾加上一个特殊符号“#”,表示输入结束。
例如:A(B(D, E(G, )), C( , F))#
看到这题就想到清华数据结构网课里,邓老师在逆波兰表达式那里介绍的“栈识别括号”的思路啦!(为邓老师疯狂打call)
#include<iostream>
#include<stack>
#include<string>
using namespace std;
stack<char> ch,alpha,l,r;//利用栈识别
template<class Type>
struct BinNode{
Type data;
BinNode <Type> *lchild;BinNode<Type> *rchild;
};//规定的二叉树格式
template<class Type> class BiTree{
friend class BinNode<Type>;
public:
BinNode<Type> *root;
BiTree(){root=new BinNode<Type>;};
void CreateBinTree(istream &in,BinNode<char> *&BT);
bool put(BinNode<char> *p);
void show(BinNode<char> *root);
};
template<class Type>
void BiTree<Type>::show(BinNode<char> *root)
{
if(root==NULL) return ;
cout<<root->data<<" ";
show(root->lchild);
show(root->rchild);
}//前序遍历的输出
template<class Type>
void BiTree<Type>::CreateBinTree(istream &in, BinNode<char> *&BT)
{ string p;in>>p;
char *pp=&p[0],temp1,temp2,q;int flag=0;
while(*pp!='#')
{
if(*pp=='(')
{ch.push(*pp);
char t=*(pp+1);
if(t==',') alpha.push('#');
else {alpha.push(t);pp++;}}
else if(*pp==',')
{if(ch.size()==1) flag=1;
ch.push(*pp);
char t=*(pp+1);
if(t==')') alpha.push('#');
else {alpha.push(t);pp++;}
if(flag==1) {r.push('&');flag=0;}}
else if(*pp==')')
{temp1=alpha.top();alpha.pop();temp2=alpha.top();alpha.pop();r.push(temp1);l.push(temp2);ch.pop();ch.pop();}
else alpha.push(*pp);
pp++;
}
BinNode<char> *n=BT;
q=alpha.top();
BT->data=q;
flag=0;
put(n);
while(1){int temp1=0,temp2=0;
temp1=put(n->rchild);
if(!temp1) break;
else {n=n->rchild;continue;}
temp2=put(n->lchild);
if(!temp2) break;
n=n->rchild;
}
n=BT->lchild;
while(!l.empty()&&!r.empty())
{ put(n);
put(n->rchild);
put(n->lchild);
n=n->rchild;
}
}
template<class Type>
bool BiTree<Type>::put(BinNode<char> *cur)
{
if(l.empty()||r.empty()) return false;
BinNode<char> *lnode=new BinNode<char>,*rnode=new BinNode<char>;
if(r.top()=='&') {r.pop();return false;}
lnode->data=l.top();l.pop();lnode->lchild=NULL;lnode->rchild=NULL;cur->lchild=lnode;
rnode->data=r.top();
{r.pop();rnode->lchild=NULL;rnode->rchild=NULL;cur->rchild=rnode;}
return true;
}
int main()
{
BiTree<char> b;
cout<<"输入广义表:"<<endl;
b.CreateBinTree(cin, b.root);
cout<<"输出二叉树(前序遍历):"<<endl;
b.show(b.root);
}
哇,好壮观
思路:规定了函数声明和二叉树节点定义,所以先写一个二叉树模版,第一次看到istream &in的参数真的好晕…
其实它的意思就是输入流,在createBinTree里用**in>>p;**就可以用指针p指向它使用啦
createBinTree思路:建立四个栈alpha,ch,r,l,依次读入广义表直到#
若是左括号,左括号入ch,其后字母入alpha(要判断后面字符是否为空,空的话入#)
若是逗号,同左括号
若是右括号,证明一棵子树就此完结,退出ch里前面的左括号和逗号,退出两个字符分别放到r和l(逆序放入,利用栈)
为了构建时的方便,我们还需要识别出左右子树转换的那一刻(即右子树摆放完毕,转向左子树的时刻)(最中间的那一个逗号)
我们发现它出现在ch里只有一个左括号的情况,在识别到这个情况时,我们在alpha里放入&作为标志
然后就可以构建出四个栈里的预备数据
put函数构建二叉树,一次建一棵,取出r里的字符放在右子树,l里的字符放在左子树
先构建好根节点和它的左右孩子,再依次对这个右孩子进行构建操作(先右再左)
如果识别到了&,返回特殊值终止对右子树的构建
然后转向对左子树的构建,直到栈空
个人觉得重点在基本思路和左右子树转换上
如果有问题可以康邓老师的视频(B站:数据结构与算法清华大学)
PS:这个写出来超开心
前序遍历非递归算法
二叉树定义同前,只是data为char类型的
拙劣的建立二叉树函数就算了,康康非递归思路
template<class Type>
void BiTree<Type>::PreOrder(BiTNode *root)
{ BiTNode *t;
stack<BiTNode *> s;
if(root==NULL) return;
s.push(root);
while(!s.empty()){
t=s.top();s.pop();
putchar(t->data);cout<<" ";
if(t->rchild!=NULL) s.push(t->rchild);
if(t->lchild!=NULL) s.push(t->lchild);
}
}
思路:还是用栈,依次入栈,每次只输出一个
要用t记录当前栈的top
最低共同祖先结点
输入二叉链表表示的二叉树中的两个结点的data,写一个递归算法输出这两个结点在树中最低的共同祖先结点,规定同一棵二叉树中不会有2个结点的data是相同的字符
template<class Type>
BiTNode * BiTree<Type>::search(BiTNode *root,char X)
{
if(root==NULL) return NULL;
if(root->data==X) return root;
BiTNode *p=search(root->lchild,X);
if(p!=NULL) return p;
return search(root->rchild,X);
}
template<class Type>
BiTNode * BiTree<Type>::getLCA(BiTNode *root,char X,char Y)
{
if(root==NULL) return NULL;
if(root->data==X||root->data==Y) return root;
int xl=0,xr=0,yl=0,yr=0;
if(search(root->lchild,X)){xl=1;xr=0;}
else if(search(root->rchild,X)){xr=1;xl=0;}
if(search(root->lchild,Y)){yl=1;yr=0;}
else if(search(root->rchild,Y)){yr=1;yl=0;}
if((xl||yl)&&(xr||yr)) return root;
else if(xl&&yl) return getLCA(root->lchild, X, Y);
else if(xr&&yr) return getLCA(root->rchild, X, Y);
return NULL;
}
递归~
先判断当前阶段的根节点是否XY其中的一个,如果有就返回根节点
然后再向左右子树中搜索XY,并作xl,cr,yl,yr的标记(search函数)
如果XY分别在root的左右两边,就返回root
如果在一边的话,就递归寻找最低公共祖先结点啦
感觉自己的递归的思路不太好……
最远结点间距离
如果把二叉树看成一个图,父子结点之间的连线看成是双向的,定义“距离”为两结点之间的边数
写一个程序,求一棵二叉树中相距最远的两个节点之间的距离
template<class Type>
int BiTree<Type>::depth(BiTNode *root)
{
if(root==NULL) return 0;
else {int l=depth(root->lchild);
int r=depth(root->rchild);
return (l<r)?r+1:l+1;}
}//当前结点的深度
template<class Type>
int BiTree<Type>::nodemax(BiTNode *root)
{
int l=depth(root->lchild);
int r=depth(root->rchild);
return l+r;
}//每个结点的最大距离
template<class Type>
int BiTree<Type>::maxDistance(BiTNode *root)
{
int max=0;BiTNode *p=root;
while(p!=NULL)
{
if(nodemax(p)>max) max=nodemax(p);
int l=nodemax(root->lchild),r=nodemax(root->rchild);
if(l>=r) p=p->lchild;
else p=p->rchild;
}
return max;
}//树的最大距离
这个其实可以归结为深度求解问题
先求出一个节点的最大深度(左右节点深度的最大值)
然后求每个节点对应的距离(左孩子节点深度+右孩子节点深度)
最后遍历一下,求整棵树对应的距离
感觉自己递归的想法都有,就是不太知道怎么写成可执行程序
要多做一些练习吧,努力去理解
加油!