首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

数据结构-二叉树非递归兑现

2012-08-27 
数据结构----二叉树非递归实现/*********构造二叉树*********/输入一串以二叉树先序序列遍历的字符,空表示

数据结构----二叉树非递归实现

/*********构造二叉树*********/

输入一串以二叉树先序序列遍历的字符,空格表示空指针。

比如这串字符:ABD123CE4F5G678(为方便阅读,以数字代替空格),以先序顺序逆推出的二叉树应是:

数据结构-二叉树非递归兑现

从中观察出构造二叉树的算法:

以字符串的遍历为循环条件,构造一个栈来存放左右孩子指针都未被赋值的节点,空指针不允许入栈。

(1)循环开始前,让头节点先入栈

(2)str[i]表示当前字符(i初始值为1),若str[i-1]不是空格,那么str[i]一定是str[i-1]的左孩子;

若是空格,那么str[i]一定不是它的左孩子,即:str[i]一定是str[i-1]的右孩子,当右孩子被连接之后,

表明双亲节点的左右孩子指针均已赋值,那么就可以将这个双亲节点弹出,简化版:

if(str[i-1] != ' '){top->leftchild = creat_node(str[i]);}else{top->rightchild = creat_node(str[i]);pop(top);}

(3)如果str[i]不是空格,在一次循环完毕之前,还应将它入栈

Warning:

这里有个问题,我们是将节点从栈中弹出来修改其左右孩子指针的,仔细一想便会发现这些栈中的“节点”

并不是真正的二叉树节点,它们只是在内存中申请了一块连续的空间来寄存真正二叉树的节点,所以我们

是不能将节点直接连到栈中的元素的

Solution:

在每个节点里附设一个指向它本身的this指针,在连接的时候在this指针的内容里赋值,这样就可以保护

真正节点的内存地址了

/*********几种遍历二叉树*********/

一、前序遍历

以上图为例,前序遍历的顺序就是:ABDCEFG

前序遍历的算法依旧要借助栈来实现:

(1)栈中存放已被访问的节点

(2)先要往左走到最底端,也就是此时节点的左孩子为NULL

(3)然后向右走一步(通过出栈来获得其双亲节点数据,将当前指针指向它的右孩子即可)

(4)以这个右孩子为新的头节点,如果它为NULL,则继续出栈获得上一个双亲节点,在向右一步,重复

这个过程,直到栈为空或者有一个节点的右孩子不为NULL

(5)有了新的头节点后,重复(2)(3),直到栈为空,也就是遍历完毕

Waring:

这里的为什么不像构造二叉树那样利用this指针?因为这里的遍历不需要改变二叉树的结构、属性,如果

遇到线索化二叉树这种需要改变其本身的遍历就应该使用this指针了

二、中序遍历

中序遍历的顺序为:DBACEFG

算法:

(1)构造栈,头节点入栈,栈中元素为存放着未被访问的节点

(2)向左走到最底端,退栈,访问这个节点,然后向右走一步

(3)以右节点为新的头节点,继续(2),直到栈为空,表示遍历结束

Waring:

中序遍历和先序遍历都需要用到栈,但是栈中元素的性质却不一样,先序遍历中栈元素需要是已被访问的节点,

这是因为双亲节点应该被首先访问;而中序遍历中栈元素须是未被访问的节点,是因为双亲节点的访问应该后于

其左孩子。

(后序遍历在其后的销毁二叉树中总结)

三、层次遍历

层次遍历顺序:ABCDEFG

算法:

(1)我们需要的不是栈了,而是队列

(2)当访问一个节点的时候,我们要考虑其左右孩子,若有不为空的孩子就让它入队列,在其双亲节点后面排队

(3)采取从左到右、从上到下的层次,每让最前端的出队列被访问时,就应该让它的不为空的孩子指针入队列

(4)当队列为空的时候,就表示遍历完毕了

/********遍历的应用**********/

一、计算节点数目

通过层次遍历可以计算,每次出队列访问一个就++count,到层次遍历结束的时候,节点数目就自然出来了

二、求二叉树深度

如果用递归的方法很简单:先求其左子树深度,再求其右子树深度,深度大的为二叉树深度

(非递归的还没想出来,求大神指教)

三、销毁二叉树

二叉树的构造是通过内存申请完成的,销毁它是必须滴~~~

采用后序遍历来销毁二叉树要简单一些,因为销毁二叉树必须要从下到上销毁,不得破坏二叉树结构,否则将不能销毁;

而后序遍历正好是这种模型

算法:

(1)利用栈,向左走到最深处

(2)这时栈顶元素的左孩子肯定为NULL,so 考虑其右孩子是否也为NULL,如不为NULL,就向右走一步;如果是NULL,

说明找到的是叶子节点,pop一下,free它,当然应该free的是this指针,因为此时我们必须改变二叉树的结构。

(3)然后再次获取栈顶元素,我们需要改变栈顶元素的左右孩子指针,我们应该修改它的左孩子还是右孩子?我们不知道

刚才free的是哪一个孩子,但是有一个定律:后序遍历同样采用从左到右的顺序,如果它的左孩子不为NULL,就应该让它的

左孩子为NULL,如果已经是NULL了,就应该让它的右孩子为NULL

(4)循环中。。。。直到栈为空、头节点被释放,表明销毁成功

四、线索化二叉树

算法:

(1)一般采用中序线索化二叉树,一个节点的左孩子指针不为空时方可进行线索化

(2)中序遍历中,我们将访问节点的部分改为对节点进行线索化,若其左孩子指针不为NULL,就让它指向其前驱,若其

右孩子指针不为NULL,就让它指向其后继,这里同样要改变二叉树结构,所以也需用到this指针

(3)确定前驱后继:附设两个遍历指针,cur指针指向当前遍历的节点,pre指针指向刚刚访问过的节点,就是cur的前驱,在

中序遍历中,就有这种相互关系来找到一个节点的前驱后继,pre是cur的前驱,cur是pre的后继





热点排行