树的学习——(递归构建二叉树、递归非递归前序中序后序遍历二叉树、根据前序序列、中序序列构建二叉树)
来源:互联网 发布:sql2000数据库 编辑:程序博客网 时间:2024/05/16 01:34
前言
最近两个星期一直都在断断续续的学习二叉树的数据结构,昨晚突然有点融汇贯通的感觉,这里记录一下吧
题目要求
给定前序序列,abc##de#g##f###,构建二叉树,并且用递归和非递归两种方法去做前序,中序和后序遍历
二叉树的数据结构
#define STACKSIZE 10005/** * 二叉树的数据结构 */typedef struct btree {struct btree *lchild;struct btree *rchild;char item;} btree;typedef btree *bt;/** * 定义顺序栈数据结构(非递归遍历) */typedef struct stack {btree *db[STACKSIZE];int top;} stack;
递归构建二叉树
构建二叉树有固定的几种考察类型:
- 根据完整的先序序列构建二叉树
- 根据前序和中序序列构建二叉树
根据先序序列构建二叉树(c语言实现)
char str[101] = "abc##de#g##f###";int count = 0;/** * 根据先序序列构建二叉树(因为涉及到对根节点指针修改,因此传递根节点指针的指针) */void createBtree(btree **t){if (str[count ++] == '#') {*t = NULL;} else {*t = (btree *)malloc(sizeof(btree));(*t)->item = str[count - 1];createBtree(&(*t)->lchild);createBtree(&(*t)->rchild);}}
递归的前序、中序、后序算法(c语言实现)
/** * 递归先序遍历二叉树 */void recPreorder(btree *t){if (t) {printf("%c", t->item);recPreorder(t->lchild);recPreorder(t->rchild);}}/** * 递归中序遍历二叉树 */void recInorder(btree *t){if (t) {recInorder(t->lchild);printf("%c", t->item);recInorder(t->rchild);}}/** * 递归后序遍历二叉树 */void recPostorder(btree *t){if (t) {recPostorder(t->lchild);recPostorder(t->rchild);printf("%c", t->item);}}
非递归前序、中序遍历算法(c语言实现)
/** * 非递归前序遍历 */void preorderTraverse(btree *t){btree *p = t;// 初始化栈stack *s = (stack *)malloc(sizeof(stack));s->top = 0;while (p || s->top > 0) {if (p) {printf("%c", p->item);s->db[s->top ++] = p;p = p->lchild;} else {p = s->db[-- s->top];p = p->rchild;}}}/** * 非递归中序遍历 */void inorderTraverse(btree *t){btree *p = t;// 初始化栈stack *s = (stack *)malloc(sizeof(stack));s->top = 0;while (p || s->top > 0) {if (p) {s->db[s->top ++] = p;p = p->lchild;} else {p = s->db[-- s->top];printf("%c", p->item);p = p->rchild;}}}
非递归后序遍历算法(c语言实现)
算法思想:
- 首先,也是找到最左边的叶子结点并把路上遇到的节点依次入栈
- 然后,弹出栈顶元素(该元素为最左边的叶子),判断(1)它是否有右节点(2)如果有右节点,是否被访问过。如果满足(1)有右节点并且(2)右节点没有访问过,说明这是后序遍历的相对根节点,因此需要将这个节点再次入栈,并且它的右节点入栈,然后重新执行第一步。否则,就访问该节点,并且设置pre为此节点,同时把将遍历节点附空值,访问进入无限循环
算法代码:
/** * 非递归后序遍历 */void postTraverse(btree *t){btree *p, *pre;p = t;pre = NULL;// 初始化栈stack *s = (stack *)malloc(sizeof(stack));s->top = 0;while (p || s->top > 0) {if (p) {s->db[s->top ++] = p;p = p->lchild;} else {p = s->db[-- s->top];if (p->rchild != NULL && p->rchild != pre) { // p为相对根节点s->db[s->top ++] = p;p = p->rchild;} else {printf("%c", p->item);pre = p;p = NULL;}}}}
注意:
严蔚敏的<<数据结构>>上有一段话很经典,摘录如下:”从二叉树遍历的定义可知,三种遍历算法之不同处仅在于访问根节点和遍历左、右子树的先后关系。如果在算法中暂且抹去和递归无关的visit语句,则三个遍历算法完全相同。因此,从递归执行过程的角度来看,前序、中序、后序遍历也完全相同。“ 这段话给我们的提示就是,前序、中序、后序遍历的算法相同,只是printf()语句位置而已。
根据前序序列、中序序列构建二叉树
函数定义
bt rebuildTree(char *pre, char *in, int len);
参数:
* pre:前序遍历结果的字符串数组
* in:中序遍历结果的字符串数组
len : 树的长度
例如:
前序遍历结果: a b c d e f g h
中序遍历结果: c b e d f a g h
算法思想
- 递归思想,递归的终止条件是树的长度len == 0
- 在中序遍历的数组中找到前序数组的第一个字符,记录在中序数组中的位置index.如果找不到,说明前序遍历数组和中序遍历数组有问题,提示错误信息,退出程序即可;找到index后,新建一个二叉树节点t,t->item = *pre,然后递归的求t的左孩子和有孩子
- 递归的左孩子:void rebuildTree(pre + 1, in, index)
- 递归的右孩子:void rebuildTree(pre + (index + 1), in + (index + 1), len - (index + 1))
实现代码(c语言版)
/** * Description:根据前序和中序构建二叉树 */bt rebuildTree(char *pre, char *in, int len){bt t;if(len <= 0){ //递归终止t = NULL;}else{ //递归主体int index = 0;while(index < len && *(pre) != *(in + index)){index ++;}if(index >= len){printf("前序遍历或者中序遍历数组有问题!\n");exit(-1);}t = (struct bintree *)malloc(sizeof(struct bintree));t->item = *pre;t->lchild = rebuildTree(pre + 1, in, index);t->rchild = rebuildTree(pre + (index + 1), in + (index + 1), len - (index + 1));}return t;}
根据中序序列、后序序列构建二叉树
函数定义
/** * 中序、后序序列构建二叉树 */btree* rebuildTree(char *order, char *post, int len);
算法思想
中序序列:C、B、E、D、F、A、H、G、J、I
后序序列:C、E、F、D、B、H、J、I、G、A
递归思路:
- 根据后序遍历的特点,知道后序遍历最后一个节点为根节点,即为A
- 观察中序遍历,A左侧CBEDF为A左子树节点,A后侧HGJI为A右子树节点
- 然后递归的构建A的左子树和后子树
实现代码(c代码)
/** * 根据中序和后序序列构建二叉树 * (ps:昨晚参加阿里笔试,等到最后说可以免笔试直接面试,今天估计还是要根据学校筛选,哈哈,为了这点 * 也得参加阿里笔试,不能让自己的学校受到鄙视) */#include <stdio.h>#include <stdlib.h>#include <string.h>int n;typedef struct btree {struct btree *lchild;struct btree *rchild;char data;} btree;/** * 中序、后序序列构建二叉树 */btree* rebuildTree(char *order, char *post, int len){btree *t;if (len <= 0) {return NULL;} else {int index = 0;while (index < len && *(post + len - 1) != *(order + index)) {index ++;}t = (btree *)malloc(sizeof(btree));t->data = *(order + index);t->lchild = rebuildTree(order, post, index);t->rchild = rebuildTree(order + index + 1, post + index, len - (index + 1));}return t;}/** * 前序遍历二叉树 */void preTraverse(btree *t){if (t) {printf("%c ", t->data);preTraverse(t->lchild);preTraverse(t->rchild);}}int main(void){int i;char *post, *order;btree *t;while (scanf("%d", &n) != EOF) {post = (char *)malloc(n);order = (char *)malloc(n);getchar();for (i = 0; i < n; i ++)scanf("%c", order + i);getchar();for (i = 0; i < n; i ++)scanf("%c", post + i);t = rebuildTree(order, post, n);preTraverse(t);printf("\n");free(post);free(order);}return 0;}
递归清理二叉树
复习了c语言的内存分配,参考链接:http://blog.csdn.net/zinss26914/article/details/8687859, 要点就是malloc分配的内存在堆上,使用完后应该由程序员手动释放,这里写一下递归清理二叉树的代码
/** * 清理二叉树 */void cleanBtree(btree *t){if (t) {cleanBtree(t->lchild);cleanBtree(t->rchild);free(t);}}
后记
2012年今天是最后一天了,哈哈,终于把二叉树该掌握的部分都掌握了,还是不错的,期待新的一年2013年有更多的收获,2013年可能又是我人生发生抉择和变化的一年,我依然会坚持自己的价值观,踏踏实实的走下去,现在我学会最多的就是坚持,坚忍,光说不做是没有的,写程序如此,做人亦如此!
今天是2013年7月23日,重写了部分二叉树操作的代码,对指针的掌握和对数据结构的掌握更加熟练,希望校招一切顺利,自己加油!
- 树的学习——(递归构建二叉树、递归非递归前序中序后序遍历二叉树、根据前序序列、中序序列构建二叉树)
- 某国内IT大牌名企校招笔试 + 树的学习—(递归构建二叉树、递归非递归前序中序后序遍历二叉树、根据前序序列、中序序列构建二叉树)
- 构建二叉树(据后序遍历序列)---后续遍历二叉树(递归与非递归)
- 递归构建二叉树---中序遍历二叉树(递归与非递归)
- 二叉树的前序遍历(递归+非递归)
- 构建二叉树(据前序遍历结果)--- 前序遍历二叉树(递归与非递归)
- 如何利用前序遍历序列和中序遍历序列非递归的创建二叉树
- 二叉树的非递归遍历——前序
- 【二叉树遍历算法】——前/中/后序递归与非递归的实现
- 非递归前序遍历二叉树
- 前,中,后序遍历二叉树 (递归 && 非递归的栈 && 非递归非栈的线索二叉树)
- 二叉树的非递归【前/中/后 序遍历】
- 二叉搜索树的后序遍历序列(递归与非递归)
- 数据结构学习笔记-二叉树的前、中、后序遍历,递归、非递归方式
- 接前-中序遍历二叉树(非递归)
- 二叉树的建立(根据遍历结果构建)、遍历(非递归)和搜索
- 二叉树的前序遍历(非递归)
- 二叉树的创建,遍历(前序,中序,后序)-递归 非递归
- 面相学在HR管理中的应用 .
- 隐藏Status bar(状态栏)、NavigationBar(导航栏)、tabBarController(标签栏)
- 数独之Uniqueness Test 1
- Struts2的注解功能
- unix load sql的使用
- 树的学习——(递归构建二叉树、递归非递归前序中序后序遍历二叉树、根据前序序列、中序序列构建二叉树)
- 冒烟测试
- 在工作中学习
- Dijkstra算法
- 系统架构师书籍推荐
- 有关tomcat的日志文件(一)
- 利用Altium Design将图片转化为PCB【做自己的PCB LOGO】
- JQuery向ashx提交中文参数方案
- srand()以及rand()函数用法