二叉树

1. 熟悉树的概念以及相关概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:每个结点有零个或多 个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结 点可以分为多个不相交的子树 。

节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6 叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I...等节点为叶节点
非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G...等节点为分支节点 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推; 树的高度或深度:树中节点的最大层次; 如上图:树的高度为4 堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙 森林:由m(m>=0)棵互不相交的树的集合称为森林; 

树的表示方法::双亲表 示法,孩子表示法、孩子兄弟表示法等等。最常用的是孩子兄弟表示法。

struct Node
{
	struct Node *_firstChild1;		//第一个孩子节点
	struct Node *_pNextBrother;		//指向其下一个兄弟节点
	DataType _data;					//节点中的数据域
};


2. 了解树的存储方式以及其区别

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的 浪费。而现实中使用中只有堆才会使用数组来存储,关于堆我们后面的章节会专门讲解。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表 中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结 点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链,后面课程学到高阶数据 结构如红黑树等会用到三叉链。


3. 了解树的应用场景

文件系统
4. 熟悉二叉树的基本概念以及性质

概念:一棵二叉树是节点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

性质:1. 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。 
           2. 二叉树的子树有左右之分,其子树的次序不能颠倒。
5. 熟悉满二叉树和完全二叉数,并掌握其区别

满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是 说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。

完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K 的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对 应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树(完全二叉树是满二叉树从最后一个节点往前面删减形成的二叉树)。


6. 实现链式数据结构的以下基本操作:

typedef char BTDataType;

typedef struct BTNode
{
struct BTNode* _pLeft;
struct BTNode* _pRight;
BTDataType _data;
}BTNode;

typedef struct {
    BTNode *node;    // 构建出的二叉树的根结点
    int used;    // 构建过程中使用的序列长度
}Result;


// 1. 创建二叉树
BTNode* CreateBinTree(BTDataType* array, int size);

Result CreateBinTree(BTDataType array[], int size)
{
	Result result;
	if (size == 0)
	{
		result.node = NULL;
		result.used = 0;
		return result;
	}

	if (array[0] == '#')
	{
		result.node = NULL;
		result.used = 1;
		return result;
	}

	//根
	BTNode *pRoot = (BTNode *)malloc(sizeof(BTNode));
	pRoot->_data = array[0];

	//左子树
	Result leftR = CreateBinTree(array + 1, size - 1);

	//右子树
	Result rightR = CreateBinTree(array + 1 + leftR.used, size - 1 - leftR.used);

	pRoot->_pLeft = leftR.node;	
	pRoot->_pRight = rightR.node;	

	result.node = pRoot;
	result.used = 1 + leftR.used + rightR.used;
	return result;
}



// 拷贝二叉树
BTNode* CopyBinTree(BTNode* pRoot);

BTNode* CopyBinTree(BTNode* pRoot)
{
	BTNode *newNode = NULL;
	if (pRoot == NULL)
		return NULL;
	else
	{
		newNode = (BTNode *)malloc(sizeof(BTNode));
		newNode->_data = pRoot->_data;
		newNode->_pLeft = CopyBinTree(pRoot->_pLeft);
		newNode->_pRight = CopyBinTree(pRoot->_pRight);
		
	}
	return newNode;
}



// 销毁二叉树
void DestroyBinTree(BTNode** pRoot);

void DestroyBinTree(BTNode** pRoot)
{
	assert(pRoot);
	if (*pRoot)
	{
		DestroyBinTree(&((*pRoot)->_pLeft));
		DestroyBinTree(&((*pRoot)->_pRight));
		free(*pRoot);
		*pRoot = NULL;
	}
}


// 二叉树的三种遍历方式
void PreOrder(BTNode* pRoot);

void PreOrder(BTNode* pRoot)	//前序遍历
{
	//空树
	assert(pRoot);
		return;
	//根节点
	printf("%c ", pRoot->_data);

	//左子树
	PreOrder(pRoot->_pLeft);

	//右子树
	PreOrder(pRoot->_pRight);
}


void PreOrderNor(BTNode* pRoot);

#include <stack>
using std::stack;
void PreOrderNor(BTNode* pRoot)		//非递归前序遍历
{
	stack<BTNode *> s;
	BTNode *cur = pRoot;
	while (!s.empty() || cur != NULL)
	{
		while (cur != NULL)
		{
			printf("%c ", cur->_data);
			s.push(cur);
			cur = cur->_pLeft;
		}

		BTNode *top = s.top();
		s.pop();

		cur = cur->_pRight;
	}
	printf("\n");
}


void InOrder(BTNode* pRoot);

void InOrder(BTNode* pRoot)		//中序遍历
{
	//空树
	assert(pRoot);
		return;

	//左子树
	InOrder(pRoot->_pLeft);

	//根
	printf("%c ", pRoot->_data);

	//右子树
	InOrder(pRoot->_pRight);
}


void InOrderNor(BTNode* pRoot);

void InOrderNor(BTNode* pRoot)		//非递归中序遍历
{
	stack<BTNode *> s;
	BTNode *cur = pRoot;

	while (!s.empty() || cur != NULL) {
		while (cur != NULL) {
			s.push(cur);
			cur = cur->_pLeft;
		}

		BTNode *top = s.top();
		s.pop();
		printf("%c ", top->_data);

		cur = top->_pRight;
	}

	printf("\n");
}


void PostOrder(BTNode* pRoot);

void PostOrder(BTNode* pRoot)		//后序遍历
{
	//空树
	assert(pRoot);
		return;

	//左子树
	PostOrder(pRoot->_pLeft);

	//右子树
	PostOrder(pRoot->_pRight);

	//根
	printf("%c ", pRoot->_data);
}


void PostOrderNor(BTNode* pRoot);

void PostOrderNor(BTNode* pRoot)		////非递归后序遍历
{
	stack<BTNode *> s;
	BTNode *cur = pRoot;
	BTNode *last = NULL;	// 上一次被完整遍历完的树的根结点

	while (!s.empty() || cur != NULL) {
		while (cur != NULL) {
			s.push(cur);
			cur = cur->_pLeft;
		}

		BTNode *top = s.top();
		if (top->_pRight == NULL) {
			printf("%c ", top->_data);
			s.pop();

			last = top;
		}
		else if (top->_pRight == last) {

			printf("%c ", top->_data);
			s.pop();

			last = top;
		}
		else {
			cur = top->_pRight;
		}
	}

	printf("\n");
}


void LevelOrder(BTNode* pRoot);

#include <queue>
using std::queue;
void LevelOrder(BTNode* pRoot)		//层序遍历
{
	assert(pRoot);
	printf("\n");

	queue<BTNode *> q;
	q.push(pRoot);	
	while (!q.empty()) {
		BTNode *front = q.front();
		q.pop();

		printf("%c ", front->_data);
		if (front->_pLeft != NULL) {
			q.push(front->_pLeft);
		}
		if (front->_pRight != NULL) {
			q.push(front->_pRight);
		}
	}
	printf("\n");
}


// 获取二叉树中节点的个数
int GetNodeCount(BTNode* pRoot);

int GetNodeCount(BTNode* pRoot)
{
	
	//递推
	//空树
	assert(pRoot);
		return 0;
	
	//左子树节点个数
	int left = GetNodeCount(pRoot->_pLeft);

	//右子树节点个数
	int right = GetNodeCount(pRoot->_pRight);

	return left + right + 1;
	
}


// 求二叉树的高度
int Height(BTNode* pRoot);

int Height(BTNode* pRoot)
{
	//空树
	assert(pRoot);
		return 0;
	
	//左子树高度
	int left = Height(pRoot->_pLeft);

	//右子树高度
	int right = Height(pRoot->_pRight);

	return ((left > right) ? left : right) + 1;
}


// 检测二叉树是否平衡O(N^2)
int IsBalanceTree(BTNode* pRoot);

//平衡二叉树:左子树是平衡二叉树 && 右子树是平衡二叉树 && 左右子树的高度不超过1
int IsBalanceTree(BTNode* pRoot)
{
	if (pRoot == NULL)
		return 1;
	int left = Height(pRoot->_pLeft);
	int right = Height(pRoot->_pRight);
	
	return IsBalanceTree(pRoot->_pLeft) && IsBalanceTree(pRoot->_pRight) && (abs(left - right) <= 1);
}


// 检测二叉树是否平衡O(N)
int IsBalanceTree_P(BTNode* pRoot, int* height);

int IsBalanceTree_P(BTNode* pRoot, int* height)
{
	//空树
	if (pRoot == NULL)
	{
		return 1;
	}

	int left = 0;
	int right = 0;
	if (IsBalanceTree_P(pRoot->_pLeft, &left) || IsBalanceTree_P(pRoot->_pRight, &right))
	{
		int ret = left - right;
		if ((ret >= 1) || (ret <= -1))
			return 1;
	}

	return 0;
}


// 获取二叉数中叶子节点的个数
int GetLeafNodeCount(BTNode* pRoot);

int GetLeafNodeCount(BTNode* pRoot)
{
	//空树
	assert(pRoot);
		return 0;

	//只有根节点的数
	if ((pRoot->_pLeft == NULL) && (pRoot->_pRight == NULL))
		return 1;

	//左子树叶子节点个数
	int left = GetLeafNodeCount(pRoot->_pLeft);

	//右子树叶子节点个数
	int right = GetLeafNodeCount(pRoot->_pRight);

	return left + right;
}


// 获取二叉树第K层节点的个数
int GetKLevelNodeCount(BTNode* pRoot, int K);

int GetKLevelNodeCount(BTNode* pRoot, int K)
{
	//空树
	assert(pRoot);
		return 0;

	//第一层
	if (K == 1)
		return 1;

	//左子树
	int left = GetKLevelNodeCount(pRoot->_pLeft, K - 1);

	//右子树
	int right = GetKLevelNodeCount(pRoot->_pRight, K - 1);

	return left + right;
}


// 获取二叉树中某个节点的双亲节点
BTNode* GetNodeParent(BTNode* pRoot, BTNode* pNode);

BTNode* GetNodeParent(BTNode* pRoot, BTNode* pNode)
{
	if ((pRoot == NULL) || (pNode == pRoot) || (pNode == NULL))
		return NULL;

	if ((pRoot->_pLeft != NULL) || (pNode->_pRight != NULL))
		return pNode;

	return GetNodeParent(pRoot, pNode);
}


// 求二叉树的镜像
void Mirror(BTNode* pRoot);

void Mirror(BTNode* pRoot)
{
	if ((pRoot == NULL) || ((pRoot->_pLeft == NULL) && (pRoot->_pRight == NULL)))
		return;

	BTNode *temp = pRoot->_pLeft;
	pRoot->_pLeft = pRoot->_pRight;
	pRoot->_pRight = temp;

	if (pRoot->_pLeft != NULL)
		Mirror(pRoot->_pLeft);

	if (pRoot->_pRight != NULL)
		Mirror(pRoot->_pRight);

}

 

内容概要:本文详细介绍了扫描单分子定位显微镜(scanSMLM)技术及其在三维超分辨体积成像中的应用。scanSMLM通过电调透镜(ETL)实现快速轴向扫描,结合4f检测系统将不同焦平面的荧光信号聚焦到固定成像面,从而实现快速、大视场的三维超分辨成像。文章不仅涵盖了系统硬件的设计与实现,还提供了详细的软件代码实现,包括ETL控制、3D样本模拟、体积扫描、单分子定位、3D重建和分子聚类分析等功能。此外,文章还比较了循环扫描与常规扫描模式,展示了前者在光漂白效应上的优势,并通过荧光珠校准、肌动蛋白丝、线粒体网络和流感A病毒血凝素(HA)蛋白聚类的三维成像实验,验证了系统的性能和应用潜力。最后,文章深入探讨了HA蛋白聚类与病毒感染的关系,模拟了24小时内HA聚类的动态变化,提供了从分子到细胞尺度的多尺度分析能力。 适合人群:具备生物学、物理学或工程学背景,对超分辨显微成像技术感兴趣的科研人员,尤其是从事细胞生物学、病毒学或光学成像研究的科学家和技术人员。 使用场景及目标:①理解和掌握scanSMLM技术的工作原理及其在三维超分辨成像中的应用;②学习如何通过Python代码实现完整的scanSMLM系统,包括硬件控制、图像采集、3D重建和数据分析;③应用于单分子水平研究细胞内结构和动态过程,如病毒入侵机制、蛋白质聚类等。 其他说明:本文提供的代码不仅实现了scanSMLM系统的完整工作流程,还涵盖了多种超分辨成像技术的模拟和比较,如STED、GSDIM等。此外,文章还强调了系统在硬件改动小、成像速度快等方面的优势,为研究人员提供了从理论到实践的全面指导。
内容概要:本文详细介绍了基于Seggiani提出的渣层计算模型,针对Prenflo气流床气化炉中炉渣的积累和流动进行了模拟。模型不仅集成了三维代码以提供气化炉内部的温度和浓度分布,还探讨了操作条件变化对炉渣行为的影响。文章通过Python代码实现了模型的核心功能,包括炉渣粘度模型、流动速率计算、厚度更新、与三维模型的集成以及可视化展示。此外,还扩展了模型以考虑炉渣组成对特性的影响,并引入了Bingham流体模型,更精确地描述了含未溶解颗粒的熔渣流动。最后,通过实例展示了氧气-蒸汽流量增加2%时的动态响应,分析了温度、流动特性和渣层分布的变化。 适合人群:从事煤气化技术研究的专业人士、化工过程模拟工程师、以及对工业气化炉操作优化感兴趣的科研人员。 使用场景及目标:①评估不同操作条件下气化炉内炉渣的行为变化;②预测并优化气化炉的操作参数(如温度、氧煤比等),以防止炉渣堵塞;③为工业气化炉的设计和操作提供理论支持和技术指导。 其他说明:该模型的实现基于理论公式和经验数据,为确保模型准确性,实际应用中需要根据具体气化炉的数据进行参数校准。模型还考虑了多个物理场的耦合,包括质量、动量和能量守恒方程,能够模拟不同操作条件下的渣层演变。此外,提供了稳态求解器和动态模拟工具,可用于扰动测试和工业应用案例分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值