二叉树与多叉树

1、 二叉树

1二叉树有两种表示方式:链表与数组,在数组中存放信息、索引、左右节点,无疑二叉树的产生将减短查找时间。对二叉树的遍历使用广度优先遍历与深度优先遍历,在深度优先遍历中使用前序、中序、后序。一般的我们在进行深度优先遍历的时候采用的是递归的思想。

其一般的定义如下:

template<class T>
class BSTNode
{
public:
	T key;
	BSTNode *left,*right;
	BSTNode()
	{
		left=right=0;
	}
	BSTNode(const T&el,BSTNode *l=0,BSTNode *r=0)
	{
		key=el;
		left=l;
		right=r;
	}
};

 

 

2但是使用递归的时候。递归调用不是纯粹表面上的函数自身调用,而是一个函数的实例调用另一个函数的实例,这些调用在内部表示为不同的记录,由操作系统进区分。

对于每个函数,它的状态是由函数的所有自动变量的内容、函数参数的值、表明从哪里返回到调用函数的返回地址所决定的,包含这些信息的数据区叫做记录或者栈结构。这个记录是函数的私有信息池,存储了程序正确执行并正确返回到调用它的函数所需的所有信息,活动记录的寿命一般很短,在函数开始执行时,对齐的空间分配是动态进行的。

由此可知,递归调用,系统内部付出的代价会很高,于是我们进行前序树遍历的非递归实现,使用一个栈进行,而在广度优先遍历的时候我们采用的是队列存储元素的数据。

3)但是当树在最坏的情况下,这个栈几乎要包含树中所有的信息。于是我们使用了一种叫做线索树的结构,每个节点有原来的左右节点,本身的信息,还有前驱后驱。为了简化,我们将前驱与左子树使用同个指针,另使用一个变量来进行说明区分,在右子树与后继一样的方式,如此完全可以不使用栈。其定义方式可以表示如下:

typedef enum PointerTag{Link,Thread};

typedef struct BiThrNode

{

int  data;

struct  BiThrNode  *lchild,*rchild;

PointerTag LTag,RTag;

}BiThrNode,*BiThrTree;

4)由此我们可以看出,它利用了一个PointerTag域进行区分,但是可否不进行任何的多余的空间或者栈进行遍历呢?答案是肯定的。

MorrisInorder算法就是先将原来的树转为右子树的方式,重新构造一棵树,然后进行遍历,遍历之后再将这棵树进行恢复。

BSTNode<T>*p=root, *tmp;
	while(p!=0)
	{
		if (p->left==0)//访问节点
		{
			visit(p);
			p=p->right;
		}
		else
		{
			p=p->left;//在有左节点时,进行访问重新构造或者转换原来的树
			while(tmp->right!=0&&tmp->right!=p)
				tmp=tmp->right;
			if (tmp->right==0)//在重新构建树,将最右下角的节点上提,
			{
				tmp->right=p;
				tmp=tmp->right;
			}
			else
			{
				visit(p);//访问节点。
				tmp->right=0;//将原来构造的树新添的右节点删除
				p=p->right;
			}
		}
	}


 

5)最后我们谈谈平衡树,在平衡树中。无疑AVL树与红黑树是非常流行的。首先我们先分析其各自的优势。红黑树,由于其性质的使然,很肯定的是它的插入、删除逻辑很复杂,但是针对随机数的效率较高,而AVL树,逻辑简单,可是每次插入或者删除的时候都要进行相应的判断,判断两边的高度。平衡性固然高。随机性降低。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值