6.2 树和二叉树-二叉树的存储结构及遍历

  • Post author:
  • Post category:其他




1、二叉树的存储结构



1.1、顺序存储结构

#define MAX_TREE_SIZE 100 // 二叉树的最大结点数
typedef int TElemType;
typedef TElemType SqBiTree[MAX_TREE_SIZE]; // 0号单元存储根结点
SqBiTree bt;



1.2、二叉链表存储结构

typedef struct BiTNode{
	TElemType data;
	struct BiTNode * lchild, * rchild;
} BiTNode, * BiTree;



1.3、三叉链表存储结构

typedef struct TriTNode{
	TElemType data;
	struct TriTNode * lchild, * rchild;
	struct TriTNode * parent;
} TriTNode, * TriTree;



1.4、双亲链表存储结构

typedef struct BiPTNode{
	TElemType data;
	int * parent;
	char LRTag;
}BiPTNode;

typedef struct BiPTree{
	BiPTNode nodes[MAX_TREE_SIZE];
	int num_node;
	int root;
}BiPTree;



2、二叉树的遍历(图解)



2.1 先序遍历:[

先访问根节点

] 根左右

先访问根节点,再先序访问左子树,再先序访问右子树

在这里插入图片描述



2.2 中序遍历:[

中间访问根节点

] 左根右

先中序遍历左子树,再访问根节点,再中序遍历右子树

在这里插入图片描述



2.3 后序遍历:[

最后访问根节点

] 左右根

先中序遍历左子树,再中序遍历右子树,再访问根节点

在这里插入图片描述



2.4 已知两种遍历序列求原始二叉树

通过【先序和中序】 或者 【中序和后序】 我们可以还原出原始的二叉树。

但通过【先序和后序】是无法还原出原始的二叉树的。




示例1


:已知,先序:ABCDEFGH, 中序:BDCEAFHG, 求后序。

答案:DECBHGFA(需要先根据先序和中序画出原始二叉树)。

在这里插入图片描述




示例2


:已知,先序:ABDGHCEFI, 中序: GDHBAECIF, 求后序。

答案:GHDBEIFCA(需要先根据先序和中序画出原始二叉树)。

在这里插入图片描述




示例3


:已知,中序:BDCEAFHG, 后序序:DECBHGFA, 求先序。

答案:ABCDEFGH(需要先根据中序和后序画出原始二叉树)。

在这里插入图片描述




3、二叉树的遍历(代码)



3.1、递归遍历二叉树描述

	//先序遍历二叉树
	/*
	采用二叉链表存储结构,Visit是对数据元素操作的应用函数
	先序遍历二叉树T的递归算法,对每个数据元素调用函数Visit。
	最简单的Visit函数是:
	Status PrintElement(TElemType e){// 输出e的值
		printf(e);					 // 使用时,加上格式串
		return OK;
	}
	// 调用实例:PreOrder(T, PrintElement);
	*/
void PreOrder(BiTree T, void (*visit)(TElemType &e)){
	if(T){
		visit(T->data); //访问结点
		PreOrder(T->lchild, visit); //遍历左子树
		PreOrder(T->rchild, visit); //遍历右子树
	}
} //PreOrder



3.2、非递归遍历二叉树描述

// 非递归中序遍历二叉树 -- start
BiTNode * GoFarLeft(BiTree T, Stack * S){
	if(!T){
		return NULL;
	}
	while(T->lchild){
		Push(S, T);
		T = T->lchild;
	}
	return T;
}
void InOrderNonRecursive(BiTree T, void (* visit)(TElemType &e)){
	Stack * S;
	BiTNode * t = GoFarLeft(T, S);// 找到最左下的结点
	while(t){
		visit(t->data);
		if(t->rchild){// 
			t = GoFarLeft(t->rchild, S);
		}else if(!StackEmpty(S)){ // 栈不空时退栈
			t = Pop(S);
		}else{// 栈空表明遍历结束
			t = NULL;
		}
	}
}



4、遍历的应用



4.1、统计二叉树中叶子结点的个数(递归先序遍历)

void CountLeaf(BiTree T, int &count){
	if(T){
		if((!T->lchild) && (!T->rchild)){
			count++;
		}
		CountLeaf(T->lchild, count); 
		CountLeaf(T->rchild, count);
	}
}



4.2、求二叉树的深度(后序遍历)




二叉树的深度

=

M

a

x

{

左子树的深度

,

 右子树的深度

}

+

1

d

e

p

t

h

=

M

a

x

{

d

l

,

 

d

r

}

+

1

\begin{aligned} &二叉树的深度=Max\{左子树的深度,\ 右子树的深度\}+1 \\ &depth=Max\{d_{l},\ d_{r}\}+1 \end{aligned}















































二叉树的深度




=




M


a


x


{



左子树的深度


,






右子树的深度


}




+




1










d


e


pt


h




=




M


a


x


{




d











l



















,







d











r



















}




+




1





















int Depth(BiTree T){
	if(!T){
		depthVal = 0;
	}else{
		depthLeft = Depth(T->lchild);
		depthRight = Depth(T->rchild);
		depthVal = 1 + (depthLeft > depthRight ? depthLeft : depthRight);
	}
	return depthVal;
}



4.3、复制二叉树(后序遍历)

//生成一个二叉树的结点
BiTNode * GetTreeNode(TElemType item, BiTNode *lptr, BiTNode *rptr){
	T = (BiTNode *)malloc(sizeof(BiTNode));
	if(!T){
		exit(1);
	}
	T->data = item;
	T->lchild = lptr;
	T->rchild = rptr;
	return T;
}

BiTNode *CopyTree(BiTNode *T){
	if(!T){
		return NULL;
	}
	if(T->lchild){
		newlptr = CopyTree(T->lchild);
	}else{
		newlptr = NULL;
	}
	if(T->rchild){
		newrptr = CopyTree(T->rchild)
	}else{
		newrptr = NULL;
	}
	newnode = GetTreeNode(T->data, newlptr, newrptr);
	return newnode;
}



4.4、按给定的

先序序列

建立二叉树

暂定:

空树用 “ ”

“根” “左子树” “右子树”

按给定的

添加空格的完整的先序序列

建立二叉树

在这里插入图片描述

Status CreateBiTree(BiTree &T){
	scanf(&ch);
	if(ch == ' '){
		T = NULL;
	}else{
		T = (BiTNode *)malloc(sizeof(BiTNode));
		if(!T){
			exit(OVERFLOW);
		}
		T->data = ch; //生成根结点
		CreateBiTree(T->lchild); //构造左子树
		CreateBiTree(T->rchild); //构造右子树
	}
	return OK;
} //CreateBiTree



4.5、由表达式序列建立二叉树

由先缀表示式建树

例如:已知表达式的先缀表示式



×

+

a

 

b

 

c

/

d

 

e

-\times+a\ b\ c/d\ e











×








+


a




b




c


/


d




e




1 带空格的表达式序列建二叉树

2

先序

表达式

后序

表达式 建立二叉树

3 原表达式 建立二叉树

原表达式 建立二叉树
void CrtExpTree(BiTree &T, char exp[]){
	InitStack(S); //运算符栈
	Push(S, '#');
	InitStack(PTR); //操作数栈
	p = exp;
	ch = *p;
	while(!(GetTop(S) == '#' && ch == '#')){
		if(!IN(ch, OP)){ //ch不是运算符
			CrtNode(t, ch); //建叶子结点并入栈
		}else{ //ch是运算符
			switch(ch){
				case '(': 
					Push(S, ch);
					break; //
				case ')':
					Pop(S, c);
					while(c != '('){
						CrtSubTree(t, c);//建二叉树并入栈
						Pop(S, c);
					}
					break;
				default: 
					while(!GetTop(S, c)&& (Precede(c, ch))){
						CrtSubTree(t, c);
						Pop(S, c);
					}
					if(ch != '#'){
						Push(S, ch);
					}
					break;// default
			}// switch
		}// else
		if(ch != '#'){
			p++;
			ch = *p;
		}
	}// while
	Pop(PTR, T);
} //CrtExpTree

//建叶子结点的算法为:
void CrtNode(BiTree &T, char ch){
	T = (BiTNode *)malloc(sizeof(BiTNode));
	T->data = ch;
	T->lchild = T->rchild = NULL;
	Push(PTR, T);
}


//建子树的算法为:
void CrtSubTree(BiTree& T, char c){
	T = (BiTNode *)malloc(sizeof( BiTNode));
	T->data = c;
	Pop(PTR, rc);
	T->rchild = rc;
	Pop(PTR, lc);
	T->lchild = lc;
	Push(PTR, T);
}



4.6、由二叉树的先序和中序序列建树

中序:左子树 根 右子树

先序:根 …

后序:… 根

例如:已知二叉树的

先序序列:abcdefg

中序序列:cdbaegf

分析可得:

根结点是 a

左子树是 cdb

右子树是 egf

=========================================================================

typedef enum PointerTag {Link, Thread};// Link==0指针, Thread==1线索
typedef int TElemType;

//线索链表,线索二叉树,线索化
typedef struct BiThrNode{
	TElemType data;
	struct BiThrNode * lchild, * rchild;//左右孩子指针
	PointerTag LTag, RTag;// 左右标志
}BiThrNode, * BiThrTree;

// 4、线索链表存储结构