【数据结构】树笔记
创始人
2024-05-29 02:54:37
0
  1. 基础知识

树,有父节点和子节点。

二叉树分为:满二叉树,完全二叉树,完美二叉树

满二叉树:在当前树中,父节点不存在缺失左儿子或右儿子的现象。

完全二叉树:基于满二叉树,当前树中从上往下,从左至右数结点,不存在跳过空结点的现象

完美二叉树:基于完全二叉树,根节点左右子树等高

  1. 二叉树

1. 创建二叉树

树的开始处是根节点,结点可能有两个子节点。

#include
using namespace std;
template
struct p{t data;p *left_p;p*right_p;p(t num){left_p=NULL;right_p=NULL;data=num;}
};

然后尝试设置一个初始化树的函数。

template
class tree{
private:p *father;
public:tree(t n){father=new p(n);}~tree(){}

树初始化好了,出现了new结点,所以将来还要记得把树销毁掉,即析构函数。

2. 添加新结点

首先思考需要怎样才能添加一个确定的(或者说符合用户心意的)结点。

新结点的值是必定的,还需要指定新结点的父节点,并指定是要插入父节点的左子树还是右子树。

不能让用户自己创建一个结点指定,用户的输入必须简单。这里我们假设这棵树中无重复值,所以用户需要输入的树中目标结点的值。

这里涉及到一个问题,如何找到这个目标结点。于是我们先写查找结点的函数。

3. 查找结点

遍历树:先看当前结点的左子树,看完且没有找到后再看右子树->典型的递归函数

template
class tree{
private:p *father;p* refind(t n,p*r){if(r==NULL){return NULL;}if(r->data==n){return r;}p*temp_p=refind(n,r->left_p);if(temp_p==NULL){temp_p=refind(n,r->right_p);}return temp_p;}
public:tree(t n){father=new p(n);}~tree(){}p* findn(t n){return refind(n,father);}
};

回过头来说插入结点。

找到之后,首先看,如果我们要插入的是左结点,那看找到的这个结点它左结点满没满,没满,插入,满了,插入失败,插入右结点同理

int insert(t n,int flag,t num){p*temp_p=refind(n,father);if(temp_p==NULL){return 0;}if(flag==0){if(temp_p->left_p==NULL){p*new_p=new p(num);temp_p->left_p=new_p;return 1;}return 0;}else{if(temp_p->right_p==NULL){p*new_p=new p(num);temp_p->right_p=new_p;return 1;}return 0;}}

4. 遍历二叉树

已经写完了查找,遍历是一样的。

template
class tree{
private:p *father;void repre(p*temp_p){if(temp_p==NULL ){return;}cout<data<<" ";repre(temp_p->left_p);repre(temp_p->right_p);}
public:tree(t n){father=new p(n);}~tree(){}void pre(){repre(father);cout<

以上方法是前序遍历。前序遍历就是:输出顺序为:父节点,左子树,右子树

后面还有中序遍历,后序遍历。

中序遍历输出顺序为:左子树,父节点,右子树

后序遍历就是:左子树,右子树,根节点。

很明显这两个和前序遍历写法一样,除了要移动一下输出的位置。

#include
using namespace std;
template
struct p{t data;p *left_p;p*right_p;p(t num){left_p=NULL;right_p=NULL;data=num;}
};
template
class tree{
private:p *father;void repre(p*temp_p,int n){for(int i=0;idata<left_p==NULL and temp_p->right_p==NULL){return;}repre(temp_p->left_p,n+2);repre(temp_p->right_p,n+2);}void remi(p*temp_p){//中序递归if(temp_p==NULL){return ;}remi(temp_p->left_p);cout<data<<" ";remi(temp_p->right_p);}void relast(p*temp_p){//后序递归if(temp_p==NULL){return;}relast(temp_p->left_p);relast(temp_p->right_p);cout<data<<" ";}p* refind(t n,p*r){if(r==NULL){return NULL;}if(r->data==n){return r;}p*temp_p=refind(n,r->left_p);if(temp_p==NULL){temp_p=refind(n,r->right_p);}return temp_p;}
public:tree(t n){father=new p(n);}~tree(){}void preprint(){//前序repre(father,0);}void midprint(){//中序remi(father);cout<* findn(t n){return refind(n,father);}int insert(t n,int flag,t num){p*temp_p=refind(n,father);if(temp_p==NULL){return 0;}if(flag==0){if(temp_p->left_p==NULL){p*new_p=new p(num);temp_p->left_p=new_p;return 1;}return 0;}else{if(temp_p->right_p==NULL){p*new_p=new p(num);temp_p->right_p=new_p;return 1;}return 0;}}
};
int main(){treet(11);t.insert(11,0,22);t.insert(11,1,33);t.insert(22,0,44);t.insert(33,0,55);t.preprint();t.midprint();t.lastprint();
}

虽然上述都是用递归实现的,但如果树过大,系统的栈空间已满,递归将失败。所以考虑用迭代实现。

递归其实也是用栈实现的,所以说,我们完全可以用栈来代替递归过程

前序:(翻译一下递归的实现方式就好了)

void repre(){stack*>s;s.push(father);while(!s.empty()){p *temp_p=s.top();s.pop();cout<data<<" ";if(temp_p->right_p!=NULL){s.push(temp_p->right_p);}if(temp_p->left_p!=NULL){s.push(temp_p->left_p);}}}

中序:一个数要访问两次才能输出,所以再拿一个栈存。不管右结点有没有,都把它加入。

翻译一下当时做递归中序时的方法:只有空的时候才返回,说迭代的语言就是,只有空的时候才弹栈。

(这样才能越级输出根节点)

void remid(){stack*>s;//存放第一次遍历的结点stack*>s1;//存放第二次遍历的结点s.push(father);while(!s.empty()){p*temp_p=s.top();s.pop();if(temp_p==NULL){if(!s1.empty()){cout<data<<" ";s1.pop();}}else if (temp_p->left_p==NULL and temp_p->right_p==NULL) {cout<data<<" ";cout<data<<" ";s1.pop();}else{s1.push(temp_p);s.push(temp_p->right_p);s.push(temp_p->left_p);}}

后序遍历的迭代方法和中序遍历是一样的,关键点是处理什么时候彻底弹栈(即弹出s1栈)。本来想设置两个栈的,后来意识到其实我们是没有办法区分左右子树的。也就是,弹主栈的操作遇到两次,s1就要弹出一个。可以自己画图试着理解。

void relast(){stack*>s;stack*>s1;int cont=0;s.push(father);while(!s.empty()){p*temp_p=s.top();s.pop();if(temp_p==NULL){cont++;if(cont==2){if(!s1.empty()){cout<data<<" ";s1.pop();cont=1;}}}else{s1.push(temp_p);s.push(temp_p->right_p);s.push(temp_p->left_p);}}cout<

下次来补层序遍历。。。受不了了,敲不动了。

  1. 二叉查找树(BST)

这棵树左节点小于根节点,右节点大于根节点。

所以看起来,找的时候只要向一边找就行了,每次舍弃掉一半的点,算法课算过,效率是O(lgn)。

但是如果树长得很丑,比如全部只有右子树(退化成链表),这样就不存在舍弃点,所以效率就退化回O(n)

相关内容

热门资讯

中国维护国际经贸秩序的立场坚定... 应美方请求,中美经贸高层会谈在瑞士举行。中方在充分考虑全球期待、中方利益、美国业界和消费者呼吁的基础...
来自雪豹之都西宁的“礼物” 雪豹文创。本报记者 陆广涛 摄本报记者 张慧慧“这个设计很有特点!”“妈妈,我想把这个雪豹毛绒公仔带...
330千伏玉树二回接入工程 保... 本报讯 (记者 董洁 通讯员 王宏霞) “地区电力调度控制中心已下令,现在请大家按照调度指令开展作业...
开展家庭教育指导 检护少年健康... 转自:法治日报□ 本报记者 徐鹏  近日,青海省人民检察院联合省人民法院、省妇联、省教育厅、省民政厅...
成都“送体到校”活动落幕 转自:成都日报锦观惠及35000余名学生成都“送体到校”活动落幕 本报讯 (成都日报锦观新闻...
成都蓉城豪取五连胜 转自:成都日报锦观客场4∶0梅州成都蓉城豪取五连胜 本报讯 (成都日报锦观新闻记者 胡锐凯)...
节后错峰游 成都是全国第三大热... 转自:成都日报锦观节后错峰游 成都是全国第三大热门目的地 本报讯 (成都日报锦观新闻记者 杨富...
李在明登记成为韩国总统候选人 转自:成都日报锦观李在明登记成为韩国总统候选人 韩国共同民主党总统候选人李在明10日正式登记成...
结婚领证不用户口簿 还需哪些材... 转自:成都日报锦观结婚领证不用户口簿 还需哪些材料?民政部就婚姻登记“全国通办”政策作七问七答 ...
平凡铸就伟大 劳动闪耀滇池——... 在大渔街道新村社区里,有这样一位令人敬仰的劳动者——刘琼丽,她不仅是民间画的坚守者,更是一名优秀的共...
中医药非遗展讲述“生生之道” 日前,“生生之道——中医药非遗主题展”在北京中国非物质文化遗产馆开幕。展览展示了近50项传统医药类非...
从历史长河到现实岸畔的幽远沉思 王昭君、蔡文姬、冼夫人、刘禹锡、陆游、李清照、柳如是、黄遵宪……这一个个耳熟能详的名字,从杜卫东的书...
当外国人也爱上中国字 阅读提示 4月20日是第16个联合国中文日,由河南省人民政府主办,联合国教科文组织、中日韩合作...
《几生修得到梅花:有所思堂诗稿... 本报讯 近日,朱小平诗集《几生修得到梅花:有所思堂诗稿》由中国华侨出版社再版。这本诗集情真意切,旨...
母爱,铭刻在骨头里 《母爱情深》(中国青年出版社)是厉彦林纪念母亲去世十周年出版的一部散文专著。书中,作者以深沉与哀思、...
宣布停火后 印控克什米尔地区再...   当地时间10日晚,印控克什米尔地区再次传出爆炸声。  地区官员奥马尔·阿卜杜勒(Omar Abd...
绿茵燃情 高原放歌 五月的西宁,丁香绽放,花香四溢。夏都西宁·雪豹之都·丁香之城的绿茵场上,一场足球盛宴——第二届“大美...
首届中国新疆民间艺术季优秀节目... 本报讯(记者 师晓琼 摄影报道)5月9日,首届中国新疆民间艺术季优秀节目巡演青海站活动在经久不息的掌...
佩斯科夫:俄会考虑30天停火提... △佩斯科夫(资料图)  总台记者当地时间5月10日获悉,俄罗斯总统新闻秘书佩斯科夫在接受美国媒体采访...
今天是母亲节 记得跟妈妈说 我... 123海报设计:卢文茂、蒋应杰来源:中国兰州网、兰州发布编辑:柴任翔