【AVL树】

news2024/11/16 15:40:57

目录

  • 基础知识
    • AVL树的定义
    • 结点的平衡因子
    • 结构体
  • 部分操作思路
    • AVL树的插入
      • 平衡化旋转
        • 左单旋转
        • 右单旋转
        • 先左后右双旋转
        • 先右后左双旋转
      • 插入函数
    • AVl树的删除
        • 左平衡代码
        • 右平衡代码
        • 删除函数

基础知识

AVL树的定义

一棵AVL树或者是空树,或者是具有谢下列性质的二叉搜索树:他的左子树和右子树都是AVL树,且左子树和右子树的高度只差的绝对值不超过1.
在这里插入图片描述
如上图,左边的二叉搜索树每个结点的左右子树高度差的绝对值小于1,所以是AVL树,右边的树不是每个结点的左右子树高度差的绝对值小于1所以不是AVL树。

结点的平衡因子

每个结点附加一个数字,给出该结点右子树的高度减去左子树的高度所得的高度差。这个数字既是为结点的平衡因子balance。根据AVL树的定义,任何一个结点的平衡因子只能取-1,0,1。
如果一个结点的平衡因子的绝对值大于1,则这颗二叉搜索树就失去了平衡不再是AVL树。如果一棵二叉搜索树是高度平衡的,他就称为AVL树。如果他又n个结点,其高度可保持在O(log2n),平均搜索长度可保持在O(log2n)。

结构体

AVL树结构体相比于二叉搜索树多了一个平衡因子

typedef int KeyType;
typedef struct AVLNode {
	struct AVLNode* leftchild;
	struct AVLNode* parent;
	struct AVLNode* rightchild;
	int balance;
	KeyType key;
}AVLNode;
typedef struct {
	AVLNode* root;
	int cursize;
}AVLTree;

部分操作思路

AVL树的插入

在向一棵本来是高度平衡的的AVL树中插入一个数据导致出现了不平衡,我们就需要做平衡话处理,使得树中各结点重新平衡化。

平衡化旋转

  • 如果在一棵平衡的二叉搜索树中插入一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。
  • 平衡化旋转有两种类型:单旋转(左单旋和右单旋)双旋转(左平衡和右平衡)。
  • 每插入一个新结点时,AVL树中相关结点的平衡状态回发生改变。因此,在插入一个新结点后,需要从插入位置沿通向根的路径回溯,检查各个结点的平衡因子。如果发现某节点高度不平衡,停止回溯。
  • 从不平衡的结点起,沿刚才回溯的路径取直接下两层的结点。
  • 如果这三个结点处于一条直线上,则采用单旋转进行平衡化,单旋转可按其方向分为左单旋和右单旋,其中一个是另一个的镜像,其方向与不平衡的形状相关。
  • 如果这三个结点处于一条折线上,则采用双旋转进行平衡化,双旋转分为先左后右和先右后左两类。
    在这里插入图片描述

左单旋转

左单旋转的操作如下图,我们从新加入的结点向上遍历,找到平衡因子不小于等于1的结点后有如下三步操作:

  • 建立新的根节点指向平衡因子为2的结点的右孩子,
  • 将平衡银子结点为2的结点的右孩子指向新根节点的左孩子,
  • 新根节点的右孩子指向平衡因子为2的结点。

在这里插入图片描述
代码:

AVLNode* RotateLeft(AVLTree* ptree, AVLNode* ptr) {
	assert(ptree != nullptr && ptr != nullptr);
	AVLNode* newroot = ptr->rightchild;//1
	newroot->parent = ptr->parent;//1的双亲
	ptr->rightchild = newroot->leftchild;//2
	if (newroot->leftchild != nullptr) {//2的双亲
		newroot->leftchild->parent = ptr;
	}
	newroot->leftchild = ptr;//3
	AVLNode* pa = ptr->parent;
	if (pa == nullptr) {//此处ptr为n根节点
		ptree->root = newroot;
	}
	else {//ptr不是根节点
		if (pa->leftchild == ptr) {
			pa->leftchild = newroot;
		}
		else {
			pa->rightchild = newroot;
		}
	}
	ptr->parent = newroot;//3的双亲
	return newroot;
}

右单旋转

右单旋转和左单旋转是相同的思想,如下图:
在这里插入图片描述
代码:

void RotateRight(AVLTree* ptree, AVLNode* ptr) {
	assert(ptree != nullptr && ptr != nullptr);
	AVLNode* newroot = ptr->leftchild;//1
	newroot->parent = ptr->parent;//
	ptr->leftchild = newroot->rightchild;//2
	if (newroot->rightchild != nullptr) {
		newroot->rightchild->parent = ptr;
	}
	newroot->rightchild = ptr;//3
	AVLNode* pa = ptr->parent;
	if (pa == nullptr) {
		ptree->root = newroot;
	}
	else {
		if (pa->leftchild == ptr) {
			pa->leftchild = newroot;
		}
		else {
			pa->rightchild = newroot;
		}
	}
	ptr->parent = newroot;
}

先左后右双旋转

下图如果新增加
先左后右的操作如下图:
在这里插入图片描述
具体操作:在这里插入图片描述

  • 在子树F或G中插入新结点,该子树高度增加1.结点A的平衡因子变为-2,发生了不平衡。
  • 从结点A起沿插入路径选取三个结点A,B,E,他们位于一条形如’<'的折线上,因此需要进行先左后右的双旋转。
  • 我们的先左后右旋转呢实际上就是进行了两次单旋转。首先以B结点为ptr进行左单旋,然后以A结点为ptr进行右单旋。
    代码:
void LeftBalance(AVLTree* ptree, AVLNode* ptr) {//左平衡
	assert(ptree != nullptr && ptr != nullptr);
	AVLNode* leftsub = ptr->leftchild, * ringhtsub = nullptr;
	switch (leftsub->balance) {
	case 0:
		printf("tree left balance \n"); 
		break;
	case -1://新插入结点在D上 直线 右单旋
		ptr->balance = 0;
		leftsub->balance = 0;//平衡因子自行修改
		RotateRight(ptree, ptr);
		break;
	case 1://折线 左右旋转
		ringhtsub = leftsub->rightchild;
		switch (ringhtsub->balance) {
		case 0:
			ptr->balance = 0;
			leftsub->balance = 0;
			break;
		case -1:
			ptr->balance = 1;
			leftsub->balance = 0;
			break;
		case 1:
			ptr->balance = 0;
			leftsub->balance = -1;
			break;
		}
		ringhtsub->balance = 0;
		RotateLeft(ptree,leftsub);//左右单旋即先左单旋后右单旋
		RotateRight(ptree, ptr);
		break;
	}
}

先右后左双旋转

同先左后右双旋转刚好相反,思路一致,此处不多做叙述
代码:

AVLNode* RightBalance(AVLTree* ptree, AVLNode* ptr) {
	assert(ptree != nullptr && ptr != nullptr);
	AVLNode* newroot=nullptr;
	AVLNode* rightsub = ptr->rightchild, *leftsub  = nullptr;
	switch (rightsub->balance) {
	case 0:

		break;
	case 1:
		ptr->balance = 0;
		rightsub->balance = 0;
		newroot=RotateLeft(ptree, ptr);
		break;
	case -1:
		leftsub = rightsub->leftchild;
		switch (leftsub->balance) {
		case 0:
			ptr->balance = 0;
			rightsub->balance = 0;
			 break;
		case 1:
			ptr->balance = -1;
			rightsub->balance = 0;
			break;
		case -1:
			ptr->balance = 0;
			rightsub->balance = 1;
			break;
		}
		leftsub->balance = 0;
		newroot=RotateRight(ptree, rightsub);
		newroot=RotateLeft(ptree, ptr);
		break;
	}
	return newroot;
}

插入函数

向AVL树中插入数据时,刚开始同我们二叉搜索树的插入一致。我们通过新插入的结点开始向根回溯的同时判断,我们肯定要首先判断插入的位置,判断其插入的位置是左孩子还是右孩子,
左孩子:原来新插入结点的双亲结点的平衡因子是0则变为-1.原来平衡因子是1则变为0,且高度不会改变,如果是-1,我们就会发现发生了问题,平衡因子本质上已经变成了-2,所以我们进行左平衡,做了平衡操作(旋转)之后他就会变成了原来的高度,所以高度不会改变。
右孩子同左孩子类似判断即可。
代码:

void Adjust_Insert_Item(AVLTree* ptree,AVLNode* ptr) {
	assert(ptree != nullptr && nullptr != ptr);
	bool taller = true;//判断高度会不会发生改变
	AVLNode* pa = ptr->parent;
	while (pa != nullptr && taller) {//插入位置
		if (pa->leftchild == ptr) {//插入到左子树
			switch (pa->balance) {
			case 0:pa->balance = -1; break;
			case 1:pa->balance = 0; 
				taller = false;
				break;
			case -1:
				LeftBalance(ptree, pa);
				taller = false;
				break;
			}
		}
		else {//插入右子树
			switch (pa->balance) {
			case 0:pa->balance = 1; break;
			case -1:pa->balance = 0; 
				taller = false;
				break;
			case 1:
				RightBalance(ptree, pa);
				taller = false;
				break;
			}
		}
		ptr = pa;//回溯
		pa = ptr->parent;
	}
}
bool Insert_Item(AVLTree* ptree, KeyType kx) {
	assert(ptree != nullptr);
	if (ptree->root == nullptr) {//判断不存在根节点
		ptree->root = Buynode();
		ptree->root->key = kx;
		ptree->cursize = 1;
		return true;
	}
	AVLNode* ptr = ptree->root, * pa = nullptr;
	while (ptr != nullptr && ptr->key != kx) {//遍历,遍历结束找出该结点本应该存放的双亲结点
		pa = ptr;
		ptr = kx > ptr->key ? ptr->rightchild : ptr->leftchild;
	}
	if (ptr != nullptr && ptr->key == kx) return false;//树中原本就存在这个数据,直接返回错误
	//树中不存在该结点进行插入
	ptr = Buynode();//购买新节点
	ptr->key = kx;//新节点关键码赋值
	ptr->parent = pa;//双亲指针赋值
	//判断双亲结点的关键码与要插入的值的大小比较
	if (ptr->key < pa->key) {
		pa->leftchild = ptr;
	}
	else {
		pa->rightchild = ptr;
	}
	Adjust_Insert_Item(ptree, ptr);
	ptree->cursize += 1;//节点个数加一
	return true;
}

AVl树的删除

  • 如果被删除结点x最多只有一个子女,那么问题比较简单。如果被删除结点x有两个子女,首先搜索x在中序次序下的直接前驱y(同样可以找直接后继)。再把结点y的内容送给结点x,现在问题转移到和删除结点y。
  • 把结点y当作被删除结点x。
  • 将结点x从树中删除。因为结点x最多有一个子女,我们可以简单的把x的双亲结点中原来指向x的指针改指到这个子女结点;如果结点x没有子女,x双亲结点的相应指针置为NULL。然后将原来以结点x为根的子树的高度减1,++
  • 必须沿x通向根的路径反向追踪高度的变化对路径上各个结点的影响
  • 用一个布尔变量shorter来指明树的高度是否被缩短。在这个结点上要做的操作取决于shorter的值和结点的balance,有时还要以来子女的balance。
  • 布尔变量shorter的值初始化为true,然后对于从x的双亲到根的路径上的各个结点p,在shorter保持为true时执行下面的操作。如果shorter变为false,算法终止。

删除分析:
case 1:当前结点p的balance为0.如果他的左子树或右子树被缩短,则balance(下图中的3类似于p)在这里插入图片描述

case 2:结点p的balance不为0,且较高的子树被缩短,则p的balance改为0,同时shorter置为true。(下图中的7和3结点即为p)
在这里插入图片描述

case 3:结点p的balance不为0,且较矮的子树又被虽短,且在结点p发生不平衡。需要进行平衡话旋转来恢复平衡。令p的较高的子树的根为q,根据q的balance,有如下三种情况(下图中q的平衡因子大小来判断,下图均是右哦平衡为例)
case 3a:q的balance为1,我们发现他是直线,先将旋转后的平衡因子进行赋值,然后进行左单旋。
在这里插入图片描述
case 3b:q的平衡因子是0,同上,先进行旋转后的赋值,然后进行左单旋。
在这里插入图片描述
case 3c:q的平衡因子为-1,所以是折线,要进行双旋转,我们因此我们根据r的balance来判断,进行操作。在这里插入图片描述

左平衡代码

bool Adj_LeftBalance(AVLTree* ptree, AVLNode* &pa) {
	assert(ptree != nullptr && pa != nullptr);
	AVLNode* leftsub = pa->leftchild, * rightsub = nullptr;
	bool ret = false;
	switch (leftsub->balance) {
	case 0:
		pa->balance = -1;
		leftsub->balance=1;
		RotateRight(ptree, pa);
		ret = false;
		break;
	case -1:
		pa->balance = 0;
		leftsub->balance = 0;
		RotateRight(ptree,pa);
		ret = true;
		break;
	case 1:
		rightsub = leftsub->rightchild;
		switch (rightsub->balance) {
		case 0:
			pa->balance = 0;
			leftsub->balance = 0;
			break;
		case 1:
			break;
			pa->balance = 0;
			leftsub->balance = -1;
		case -1:
			pa->balance = 1;
			leftsub->balance = 0;
			break;
		}
		rightsub->balance = 0;
		RotateLeft(ptree, leftsub);
	  pa=RotateRight(ptree, pa);
		ret = true;
		break;
	}
	return ret;
}

右平衡代码

bool Adj_RightBalance(AVLTree* ptree,AVLNode* &pa){
	assert(ptree != nullptr && pa != nullptr);
	AVLNode* rightsub = pa->rightchild, * leftsub = nullptr;
	bool ret = false;
	switch (rightsub->balance){//q的平衡因子判断后面是如何旋转
	case 0:
		pa->balance = 1;
		rightsub->balance = -1;
		pa=RotateLeft(ptree,pa);
		ret = false;
		break;
	case 1:
		pa->balance = 0;
		rightsub->balance = 0;
		pa=RotateLeft(ptree, pa);
		ret = true;
		break;
	case -1:
		leftsub = rightsub->leftchild;
		switch (leftsub->balance) {
		case 0:
			pa->balance = 0;
			rightsub->balance = 0;
			break;
		case 1:
			pa->balance = -1;
			rightsub->balance = 0;
			break;
		case -1:
			pa->balance = 0;
			rightsub->balance = 1;
			break;
		}
		rightsub->balance = 0;
		RotateRight(ptree, rightsub);
		pa=RotateLeft(ptree, pa);
		ret = true;
		break;
	}
	return ret;
}

删除函数

void Adjust_Del_Tree(AVLTree* ptree, AVLNode* ptr, bool leftTag)
{
	assert(ptree != nullptr && ptr != nullptr);
	bool shorter = true;
	AVLNode* pa = ptr->parent;
	while (pa != nullptr && shorter)
	{
		if (leftTag)
		{ // pa->leftchild ==> ptr;
			switch (pa->balance)
			{
			case 0: pa->balance = 1;
				shorter = false;//本来左右高度一样,删除左孩子,高度没发生变化
				break;
			case -1: pa->balance = 0;
				shorter = true;//原本左高右低,删除左孩子,高度变化
				break;
			case 1://左低右高,删除左孩子,需要进行右平衡。
				shorter = Adj_RightBalance(ptree, pa);
				break;
			}

		}
		else
		{	// pa->rightchild ==> ptr;
			switch (pa->balance)
			{
			case 0: pa->balance = -1;
				shorter = false;
				break;
			case 1: pa->balance = 0;
				shorter = true;
				break;
			case -1:
				shorter = Adj_LeftBalance(ptree, pa);
				break;
			}
		}
		ptr = pa;
		pa = ptr->parent;
		if (pa != nullptr)
		{
			leftTag = pa->leftchild == ptr ? true : false;
		}
	}
}
bool Remove_Item(AVLTree* ptree, const KeyType kx)
{
	assert(ptree != nullptr);
	if (ptree->root == nullptr) return false;
	AVLNode* ptr = FindValue(ptree, kx);
	bool leftTag = true;
	if (ptr == nullptr) return false;
	if (ptr->leftchild != nullptr && ptr->rightchild != nullptr)
	{
		AVLNode* nextnode = Next(ptr); // Prev(ptr);
		ptr->key = nextnode->key;
		ptr = nextnode;
	}
	// del leaf; del oneBrch
	AVLNode* child = ptr->leftchild != nullptr ? ptr->leftchild : ptr->rightchild;
	AVLNode* pa = ptr->parent;
	if (pa != nullptr)//修改指向关系之前判断出待删除结点是双亲指针的左孩子还是右孩子
	{
		leftTag = pa->leftchild == ptr ? true : false;	
	}
	if (child != nullptr) child->parent = pa;
	if (pa != nullptr)
	{
		if (pa->leftchild == ptr)
		{
			pa->leftchild = child;
		}
		else
		{
			pa->rightchild = child;
		}
	}
	else
	{
		ptree->root = child;
	}
	if (ptr != nullptr && ptr->parent != nullptr)
	{
		Adjust_Del_Tree(ptree, ptr, leftTag); // pa = ptr->parent;
	}
	Freenode(ptr);
	ptree->cursize -= 1;
	return true;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/63840.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Docker 实战——部署 Nginx 镜像容器、Tomcat 镜像容器、MySQL 镜像容器

3.安装 Docker 可使用 yum list docker-ce --showduplicates | sort -r 命令来查看 Docker 的所有版本。 [rootDocker ~]# yum -y install docker-ce-17.12.1.ce #安装docker 4.启动 Docker 并设置开机自启 [rootDocker ~]# systemctl start docker [rootDocker ~]# syste…

uniClound云开发创建流程

uniClound是 DCloud 联合阿里云、腾讯云&#xff0c;为开发者提供的基于 serverless 模式和 js 编程的云开发平台。云服务创建项目&#xff0c;使用熟悉的js&#xff0c;轻松搞定前后台整体业务&#xff0c;使前端开发离全栈开发又进一步&#xff0c;尤其是一键生成代码的功能&…

海外的 SEO 网站如何进行优化

作为一个已经出海12年的专业平台&#xff0c;米贸搜为你整理了一份海外SEO优化方法&#xff0c;希望对你有所帮助。 无论是平台还是外贸网站&#xff0c;无论是外贸还是内销&#xff0c;一个绕不开的话题就是流量。随着各平台和外贸网站竞争的加剧&#xff0c;流量的获取成本也…

【ML】基于机器学习的心脏病预测研究(附代码和数据集,逻辑回归模型)

心脏病是人类健康的头号杀手, 全球大约1/3的人口死亡是由心脏病引起的。而我国,每年大概有几十万人口死于心脏病。如果我们可以通过提取人体相关的指标(既往病史、家族病史、血压情况、血糖情况等等),通过数据挖掘方式来分析不同特征对于心脏病的影响,或者建立电子病历,…

flink1.13.2 text文本数据迁移为orc+snappy数据解决方案

1.表结构不变(列名,分区不变),表存储和压缩算法改变 1.1. 外部表(未分区) 1.1.1. 拷贝源表结构,创建外部表 create table if not exists [目标表名] like [源表名] 示例: create table if not exists dwm_soh_estimate_nopartition_out_snappy like dwm_soh_estimate_n…

10x倍加速PDE的AI求解:元自动解码器求解参数化偏微分方程

研究背景 科学和工程中的许多应用需要求解具有不同方程系数、不同边界条件甚至不同求解域形状的偏微分方程(Partial Differential Equation&#xff0c;PDE)&#xff0c;即需要求解一个方程族而不是单个方程。这类应用经常在反问题求解、控制和优化、风险评估和不确定性量化领域…

C++GUI之wxWidgets(4)-编写应用涉及的类和方法(1)

目录wxApp ClasswxApp::OnInit()wxFrame ClasswxFrame处理的事件wxApp Class 当wxUSE_GUI1时&#xff0c;wxApp类代表应用程序本身。 除了wxAppConsole提供的特性外&#xff0c;它还可以跟踪顶部窗口(SetTopWindow())&#xff0c;并添加了对视频模式的支持&#xff08;SetDisp…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java小区宠物信息管理系统0v9l2

最近发现近年来越来越多的人开始追求毕设题目的设创、和新颖性。以往的xx管理系统、xx校园系统都过时了。大多数人都不愿意做这类的系统了&#xff0c;确实&#xff0c;从有毕设开始就有人做了。但是很多人又不知道哪些毕设题目才算是新颖、创意。太老土的不想做&#xff0c;创…

高低JDK版本中JNDI注入(上)

目录 前言&#xff1a; (一&#xff09;RMI 0x01 低版本 1.1 服务端 1.2 客户端 1.3 ExportObject.java 0x02 高版本 (二&#xff09;LDAP 0x01低版本 1.1 服务端 1.2 客户端 1.3 ExportObject.java 前言&#xff1a; 这篇文章主要是分析在高低版本JDK中JNDI注入RMI和LDA…

痞子衡嵌入式:浅析IAR下调试信息输出机制之硬件UART外设

大家好&#xff0c;我是痞子衡&#xff0c;是正经搞技术的痞子。今天痞子衡给大家分享的是IAR下调试信息输出机制之硬件UART外设。 在嵌入式世界里&#xff0c;输出打印信息是一种非常常用的辅助调试手段&#xff0c;借助打印信息&#xff0c;我们可以比较容易地定位和分析程序…

泰迪·滇西科技师范学院智能工作室分享:第一章NumPy库——先基础区别数组和列表

前言 来看NumPy库的应该都是接触到庞大数据处理的朋友吧。NumPy是一个简洁好用的数据库&#xff0c;尤其是在科学计算上&#xff0c;专为进行严格数字处理而产生的。其中的ndarray可以说是NumPy库的心脏&#xff0c;它提供了一个强大的N维数组对象&#xff0c;这一章我们先来简…

2 寄存器

寄存器 CPU是由运算器、控制器、寄存器等器件构成&#xff0c;他们依靠内部总线连接。 运算器进行信息处理&#xff1a;寄存器进行信息存储&#xff1b;控制器控制各种器件进行工作&#xff1b;内部总线连接各种器件&#xff0c;在它们之间进行数据的传送。 寄存器是程序员可…

[附源码]Python计算机毕业设计Django社区住户信息管理系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

AI 绘画整体认知

体验 ChatGPT 之后&#xff0c;深刻感觉到 “了解 AI 绘画” 这件事必须得安排上了。 于是用了两三个日夜&#xff0c;了解如下&#xff1a; &#xff08;文末附完整脑图链接&#xff09; 一、发展时间线 二、使用已有的AI绘画云平台&#xff08;目前国内外有很多&#xff09…

华为与思科路由器静态路由配置

一、华为路由器配置静态路由 1、静态路由基础 拓扑如下: 配置静态路由,使得PC1可以ping通PC3。 R1: interface Ethernet0/0/0ip address 124.16.8.1 255.255.255.0 # interface Ethernet0/0/1ip address 110.69.70.1 255.255.255.0 # # ip route-static 172.16.3.0 255.25…

Java_笔记_继承_虚方法表_成员变量方法构造_thisSuper

一、继承的概念以及优势&#xff1a; 1.概念&#xff1a; 1&#xff09;继承是面向对象三大特征&#xff08;封装&#xff0c;继承&#xff0c;多态&#xff09;之一&#xff0c;可让类与类之间产生子父的关系。 2&#xff09;封装&#xff1a;对象代表什么&#xff0c;就封装…

VCS Design Compiler(1)

|||||||||||| ========= =============================== VCS & Design Compiler 联合应用 =================================

[附源码]JAVA毕业设计流行病调查平台(系统+LW)

[附源码]JAVA毕业设计流行病调查平台&#xff08;系统LW&#xff09; 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1…

PTA 7-251 汉诺塔问题

PTA 7-251 汉诺塔问题 分数 100 作者 于延 单位 哈尔滨师范大学 任务描述 在印度&#xff0c;有这么一个古老的传说&#xff1a;在世界中心贝拿勒斯&#xff08;在印度北部&#xff09;的圣庙里&#xff0c;一块黄铜板上插着三根宝石针。印度教的主神梵天在创造世界的时候&am…

DBCO 点击化学试剂:DBCO-PEG24-O-NH2,DBCO-PEG24-O-amine

DBCO-PEG24-O-amine中叠氮化物和DBCO基团&#xff0c;DBCO 点击化学可以在水性缓冲液中运行&#xff0c;也可以在有机溶剂取决于底物分子的性质。带有 PEG 臂的试剂会增加化合物的亲水性。DBCO 试剂已广泛应用于生物偶联、标记和化学生物学。 西安凯新生物科技有限公司​DBCO系…