首页 > 其他分享 >第五章 树与二叉树

第五章 树与二叉树

时间:2023-08-28 18:56:39浏览次数:37  
标签:lchild 结点 遍历 第五章 二叉树 rchild NULL

一、二叉树

链式存储结构

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

遍历

先序遍历

递归版

	void PreOrder(BiTree T)
	{
		if(T != NULL)
		{
			visit(T);//访问根结点
			PreOrder(T->lchild);//递归遍历左子树
			PreOrder(T->rchild);//递归遍历右子树
		}
	}

非递归版

	void PreOrder2(BiTree T)
	{
		Stack S;
		BiTree p = T;
		InitStack(S);
		while(p || !IsEmpty(S)) //栈不空或p不空时循环
		{
			if(p) //一路向左遍历
			{
				visit(p);//先序遍历,先访问根结点
				Push(S,p);//并入栈
				p = p->lchild; //左孩子不空,一直向左走
			}
			else //p空,出栈回溯,并转向出栈结点的右子树
			{
				Pop(S,p); 
				p = p->rchild; //转向根结点的右子树进行先序遍历
			}
		}
	}

中序遍历

递归版

void InOrder(BiTree T)
{
	if(T != NULL)
	{
		InOrder(T->lchild); //递归遍历左子树
		visit(T); //访问根结点
		InOrder(T->rchild); //递归遍历右子树
	}
}

非递归版

void InOrder2(BiTree T)
{
	Stack S;
	BiTree p = T;
	while(p || !IsEmpty(S)) //栈不空或p不空时循环
	{
		if(p) //一路向左遍历
		{
			Push(S,p);
			p = p->lchild;
		}
		else //p空,出栈回溯,并转向出栈结点的右子树
		{
			Pop(S,p);
			visit(p); //访问根结点
			p = p->rchild;//转向根结点的右子树进行中序遍历
		}
	}
}

后序遍历

递归版

void PostOrder(BiTree T)
{
	if(T != NULL)
	{
		PostOrder(T->lchild);
		PostOrder(T->rchild);
		visit(T);
	}
}

非递归版

思想:按照“根右左”的顺序遍历,将结果保存到栈中,最后依次出栈访问,恰好得到“左右根”的访问顺序。

void PostOrder(BiTree T)
{
	Stack s1,s2;
	BiTree p = T;
	while(p || !IsEmpty(s1)) //栈不空或p不空时循环
	{
		if(p) //一路向右遍历
		{
			Push(s2,p);
			Push(s1,p);
			p = p->rchild;
		}
		else //p空,出栈回溯,并转向出栈结点的左子树
		{
			Pop(s1,p);
			p = p->lchild;//转向根结点的左子树进行遍历
		}
	}
	while(!IsEmpty(s2))
	{
		Pop(s2,p);
		visit(p);//访问每个结点
	}
}

层序遍历

void LevelOrder(BiTree T)
{
	Queue Q;
	BiTree p;
	InitQueue(Q);
	EnQueue(Q,T);
	
	while(!IsEmpty(Q))
	{
		DeQueue(Q,p);
		visit(p);
		if(p->lchild != NULL) EnQueue(Q,p->lchild);
		if(p->rchild != NULL) EnQueue(Q,p->rchild);
	}
}

线索化

存储结构

typedef struct ThreadNode
{
	ElemType data;
	struct ThreadNode *lchild,*rchild;
	int ltag,rtag;//左右线索标志,0表示左右孩子,1表示线索
}ThreadNode,*ThreadTree;

构造(以中序为例)

	void InThread(ThreadTree &p,ThreadTree &pre)
	{
		if(p != NULL)
		{
			InThread(p->lchild,pre); //递归,线索化左子树
			if(p->lchild == NULL) //若左子树为空,建立前驱结点
			{
				p->ltag = 1;
				p->lchild = pre;
			}
			if(p->rchild == NULL && pre != NULL) //建立上一个结点的后驱结点
			{
				pre->rtag = 1;
				pre->rchild = p;
			}
			InThread(p->rchild,p);//递归,线索化右子树,更新当前结点为刚刚访问的结点
		}
		
	}

主过程算法

void CreateInThread(ThreadTree T)
{
	ThreadTree pre = NULL;
	if(T != NULL)
	{
		InThread(T,pre);
		pre->rchild = NULL;//处理遍历的最后一个结点
		pre->rtag = 1;
	}
}

遍历(以中序为例)

求中序线索二叉树中中序序列下的第一个结点

TreeNode *Firstnode(ThreadNode *p)
{
	while(p->ltag == 0) p = p->lchild; //最左下结点(不一定叶结点)
	return p;
}

求中序线索二叉树中结点p的后继

TreeNode *nextnode(ThreadNode *p)
{
	if(p->rtag == 0) return Firstnode(p->rchild);
	else return p->rchild;
}

不含头结点的中序线索二叉树的中序遍历的算法

	void Inorder(ThreadNode *T)
	{
		for(ThreadNode *p = Firstnode(T);p != NULL;p = nextnode(p))
		{
			visit(p);
		}
	}

二、树和森林

存储结构

双亲表示法(顺序存储)

#define MAX_TREE_SIZE 100
typedef struct{
	ElemType data;
	int parent;
}PTNode;

typedef struct{
	PTNode nodes[MAX_TREE_SIZE];
	int n;
}PTree;

孩子兄弟表示法(链式存储) 树转换成森林

typdef struct CSNode{
	ElemType data;
	struct CSNode *firstchild,*nextsibling;//第一个孩子和右兄弟指针
}CSNode,*CSTree;

相互转换方法

树转换成二叉树:大家变小家,双亲管老大,大孩管小孩

  1. 在兄弟之间加一条线
  2. 对每个结点,只保留它与第一个孩子的连线,与其他孩子的连线全部删去
  3. 以树根为轴心,顺时针旋转45°

森林转换成二叉树:先把每棵树转换成二叉树,再连接每棵二叉树的根结点

二叉树转换成森林

  1. 断开右子树,直到无右结点为止
  2. 连接每个结点左孩子的右孩子,直到无右子树为止
  3. 删去每个结点最初存在的右链

树和森林的遍历与二叉树遍历的对应关系

森林 二叉树
先序遍历 先序遍历 先序遍历
后根遍历 中序遍历 中序遍历

标签:lchild,结点,遍历,第五章,二叉树,rchild,NULL
From: https://www.cnblogs.com/zjq182/p/17655082.html

相关文章

  • 二叉树的层序遍历
    /***Definitionforabinarytreenode.*publicclassTreeNode{*intval;*TreeNodeleft;*TreeNoderight;*TreeNode(){}*TreeNode(intval){this.val=val;}*TreeNode(intval,TreeNodeleft,TreeNoderight){......
  • 树和二叉树的基本概念
    树和二叉树的基本概念树的定义树是一个递归的定义了,也就是说树中一个结点和其孩子结点都可以看成一个树.树有多种表示方式但是我们通常使用第一种递归的定义来表示树结构.树的基本术语根结点:非空树中没有前驱结点的结点.结点的度:结点拥有的子树数,也就是该结点向下直接......
  • 剑指Offer 32 - III. 从上到下打印二叉树
    题目链接:剑指Offer32-III.从上到下打印二叉树题目描述:请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。解法思路:本题在一题的基础上,区分打印方向,加一个bool型的方向变......
  • 剑指Offer 32 - II. 从上到下打印二叉树 II
    题目链接:剑指Offer32-II.从上到下打印二叉树II题目描述:从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。解法思路:本题与上题的唯一区别就是在输出的时候,要将同一层的数输出在一行,这就意味着你需要知道哪些数是在一行的;这里巧妙的利用求队列......
  • 剑指Offer 32 - I. 从上到下打印二叉树
    题目链接:剑指Offer32-I.从上到下打印二叉树题目描述:从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。解法思路:本题就是从考察二叉树的层序遍历,直接上代码:代码:/***Definitionforabinarytreenode.*typeTreeNodestruct{*Valint......
  • 二叉树层序遍历队列实现
    参考:二叉树的层序遍历(两种方法实现)_askunix_hjh的博客-CSDN博客题解|#求二叉树的层序遍历#_牛客博客(nowcoder.net)题解二:BFS(迭代)主要思路:广度优先8.27用到的思路是广度优先,循环,不是递归......
  • 剑指Offer 28. 对称的二叉树
    题目链接:剑指Offer28.对称的二叉树题目描述:请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的。例如,二叉树[1,2,2,3,4,4,3]是对称的。解法思路:采用递归的方法,依次遍历根节点的左子树和右子树,判断左子树的左子树与右子树的右......
  • 剑指Offer 27. 二叉树的镜像
    题目链接:剑指Offer27.二叉树的镜像题目描述:请完成一个函数,输入一个二叉树,该函数输出它的镜像。解法思路:此题本质上就是一个二叉树遍历的问题:在遍历的过程中,交换左右子树即可。代码:/***Definitionforabinarytreenode.*typeTreeNodestruct{*Valint......
  • [刷题记录Day22]Leetcode二叉树
    No.1题目二叉搜索树的最近公共祖先思路递归法BST特性如何利用?在BST中,公共祖先一定在p、q数值范围的中间利用BST特性定向搜索注意递归遍历一条边和遍历整棵树的写法不同递归分析返回值:节点,参数:当前节点,p,q终止逻辑:发现当前节点为空,则直接返回当前节点;为什么不用判断p......
  • 二叉树的链式存储结构 C++代码实现
    /*二叉树的链式存储结构*/#include<iostream>usingnamespacestd;/*二叉链表的定义*/typedefstructBiTNode{chardata;structBiTNode*lchild,*rchild;}BiTNode;typedefBiTNode*BiTree;//*************************************************......