DS:二叉树

本周学了二叉树,感觉还挺好玩的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;
}//树的最大距离

这个其实可以归结为深度求解问题
先求出一个节点的最大深度(左右节点深度的最大值)
然后求每个节点对应的距离(左孩子节点深度+右孩子节点深度)
最后遍历一下,求整棵树对应的距离


感觉自己递归的想法都有,就是不太知道怎么写成可执行程序
要多做一些练习吧,努力去理解
加油!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值