目次
1.二叉树的烧毁
2.层序遍历
2.1深度优先搜索
2.1.1满(完全)二叉树引入
2.1.2什么是广度优先搜索
2.2广度优先搜索
2.2.1基本思绪
2.2.2代码解析
3.完全二叉树的判定
3.1思绪分析
3.2原理剖析
3.3代码分析
4.逆推二叉树结构
1.二叉树的烧毁
- //二叉树的销毁
- void treedestory(btnode* root)
- {
- if (root == NULL)
- {
- return;
- }
- treedestory(root->left);
- treedestory(root->right);
- free(root);
- }
复制代码 这个就是二叉树的末了工作,二叉树的烧毁,我们判定这个root节点,如果是空的,就可以直接返回,阐明这个二叉树上面是没有节点的,我们不需要烧毁了;
否则我们就需要利用递归的方法,把这个root的左节点和右节点依次进行删除烧毁处置惩罚,末了把这个节点释放掉;
2.层序遍历
2.1深度优先搜索
2.1.1满(完全)二叉树引入
对于上面的这个简朴的二叉树,起首我们要知道这个二叉树不是一个完全二叉树,我们要分清楚这个满二叉树和完全二叉树(反面我们会有先容,我们会有相应的代码去判定这个已知的二叉树是不是一个完全二叉树),这个满二叉树就是很好判定的,就是这个完全二叉树不轻易辨别,我们反面会详细先容;
2.1.2什么是广度优先搜索
广度优先搜索,简称就是DFS这个D就是depth,在英文里面就是广度深度的意思,F是first的第一个字母,S就是search,英文释义就是搜索的意思;
对于上面展示的这个二叉树,我们需要注意的就是这个广度就是一条路走到黑,不到黑就不会回头,我们的这个遍历顺序就是abebfbg以此类推,我上面写的顺序一个字母出现两次只是方便大家的理解,实际上这个真实的遍历,肯定不会出现两次的,就是广度优先遍历就会一条路一直向下走,走到E之后发现没有下一个节点了,他才会回头,因为这个是到达B之后开始分叉的,这个时候他就会重新回到B选择F的这一条路径,走到F之后就会发现这个又走不下去了,这个时候就会继承掉头,以此类推进行下去;
2.2广度优先搜索
2.2.1基本思绪
这个就是按照一行一行的顺序进行遍历的,这个顺序是很清楚的,一般不会出现题目,而且这个思绪也是很清楚的,我们在这个层序遍历的过程中会打印输出这个遍历的效果,实际上就是一层一层的读取的效果;
- void treelevelorder(btnode* root)
- {
- quene q;
- queneinit(&q);
- if (root)
- {
- quenepush(&q, root);
- }
- while (!queneempty(&q))
- {
- //取出来队列里面的第一个元素
- btnode* front = quenefront(&q);
- //队列元素出栈
- quenepop(&q);
- printf("%d ", front->data);
- if (front->left)
- {
- quenepush(&q, front->left);
- }
- if (front->right)
- {
- quenepush(&q, front->right);
- }
- }
- //队列的销毁
- quenedestory(&q);
- }
复制代码 2.2.2代码解析
treelevelorder就是这个层序遍历函数的简写,这个名字并不是乱取的,level有这个程度的意思,也有层级的意思,order这个就很轻易理解了,就是遍历的意思,我们之前先容的前序遍历,中序遍历,后序遍历都是利用的这个单词;
这个里面因为是利用的C语言实现的,我们起首需要构建一个对列出来,为什么要构建一个队列,因为我们这个广度优先搜索的代码就是利用的队列的相关思想,我们让一个二叉树里面的元素一个一个的进去,就是用的quenepush函数,然后再让这个quenefront函数取出来这个队列里面的第一个元素,这个元素节点的数值末了打印出来,设置循环和递归依次进行,末了得到的这个打印的效果就是所有的层序遍历的效果;
这个quenepop之后还可以找到这个对应的数值吗,这个是刚开始学的时候不少初学者的疑问,实际上这个是不会冲突的,因为这个pop的是我们自己构建的队列,我们的这个队列每一个元素都是一个指针,指向的就是这个二叉树里面的每一个节点,我们把这个队列里面的节点给释放掉了,这个二叉树里面的元素师依然可以被取出来的;
3.完全二叉树的判定
3.1思绪分析
这个如何去判定一个二叉树是不是一个完全二叉树,我们利用的方法就是上面先容的层序遍历,空的节点也需要进入队列,我们这个基本思绪照旧利用的队列的入队列和出队列的方法去进行判定;
那下面的第一个二叉树进行举例,显示让1这个节点进入队列,然后1节点出来,24节点进入(这个节点的两个子节点进入),然后2出来,2的两个子节点36进入,接下来就是4出来他的两个子节点(都是空的,但是上面写了,空的也是需要入队列的),接下俩就是3出队列,两个空节点入队列,接下里就是6这个节点出队列,他的两个子节点入队列,接下来就是4的子节点入队列,这个时候已经是空的了,且这个4的子节点反面没有非空的节点,我们这个时候就可以去判定这个二叉树就是一个完全二叉树;
同理我们去分析一下第二个二叉树,我们已经知道这个不是一个完全二叉树,先1进入队列,然后1出队列,24进入队列,然后2出队列,3和空进入队列,然后就是4出队列56进入队列,接下来就是3出队列,空空进入队列,接下来就是空出队列,但是这个空节点的反面另有两个节点没有出队列,这个时候就可以断定这个二叉树不是一个完全二叉树了;
3.2原理剖析
不直达大家有没有这个疑问,到底什么是真正的完全二叉树,到底有多少人真正的理解了这个完全二叉树的定义,虽然这个并不像离散数学那样对于这个二叉树的定义那么严及格的考察,但是我们照旧应该相识的;
老师在报告的时候,直接告诉我们下面的第二个图片不是完全二叉树,我其时就心存疑惑,到底什么是真正的完全二叉树,为什么第二个不是完全二叉树;
下面的这个就是我在网络上面找到的一个比力满足的回复,就是通过编号和满二叉树的编号进行比力,就可以确定这个二叉树是不是一个完全二叉树;如果明白了面的这个原理,我们就可以很清楚的辨别出来上面的图片里面的第二个二叉树不是一个完全二叉树
3.3代码分析
下面的这个代码是完全按照上面的这个思绪去实现的,我们先创建一个队列,然后去进行初始化,为什么这个里面会有两个while循环;
我们只需要那上面的一个案例测试一下即可,就选择上面的第二个案例吧,第二个不是完全二叉树
我们的1进入这个循环,1出来之后这个24节点进入,2出来之后3和空进入,4出来之后56进入,3出来之后这个空空进入,这个时候轮到空节点了,这个时候跳出了第一个while循环,但是这个时候的56节点已经进入了这个队列,我们执行第二个循环的时候,是可以进去的这个时候有节点,所以会进入if语句,返回false;
相反,对于这个完全二叉树而言,就像第一个二叉树,我们就可以跳出这个循环,第二个循环他是不会进入的,因为这个时候队列里面已经没有数据了,我们这个时候就会直接返回true,表明这个二叉树就是一个完全二叉树,第二个while循环就是为非完全二叉树准备的;
- bool treecomplete(btnode* root)
- {
- quene q;
- queneinit(&q);
- while (!queneempty(&q))
- {
- //取出队列里面的第一个元素
- btnode* front = quenefront(&q);
- //出队列
- quenepop(&q);
- if (front == NULL)
- {
- break;
- }
- quenepush(&q, front->left);
- quenepush(&q, front->right);
- }
- while (!queneempty(&q))
- {
- btnode* front = quenefront(&q);
- quenepop(&q);
- if (front == NULL)
- {
- quenedestory(&q);
- return false;
- }
- }
- quenedestory(&q);
- return true;
- }
复制代码 4.逆推二叉树结构
我们在这个离散数学里面也有这个类似的标题,但是其时在这个离散数学里面是有这个对应的符号,我们可以有相应的方法,在数据结构里面没有其他的符号,我们只能自己去推理;
通常情况下给的就是前序遍历和中序遍历,让我们去写这个后序遍历,我们要根据这个前序遍历和中序遍历把这个二叉树的结构给推理出来,然后再去写出这个对应的后序遍历效果;
我们方法就是采用的分割法,先是把这个中序效果给分隔开,根据这个前序遍历,我们就可以确定这个1就是树根,我们就把这个中序效果从1分隔开,然后联合这个前序遍历效果依次进行分析;
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |