数据结构平衡二叉树的操作演示

合集下载

二叉树的遍历ppt课件

二叉树的遍历ppt课件
后序遍历:若二叉树非空,则先遍历左子树,再 遍历右子树,最后访问根节点。
后序遍历顺序:
A
B
C
DE
F
中 序遍历 : 资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
DBEAF
C
前序遍历: A B D E C F
后序遍历
A
B
C
D EF
二叉树
资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
总结:
我们这节课主要采用“案例驱动式”教 学方法讲解了二叉树的遍历,以案例方式讲 解通过其中两种遍历顺序推断出第三种遍历 顺序的分析方法。主要培养大家灵活运用知 识的能力和举一反三的分析能力。
一棵二叉树的中序遍历结果为 DBEAFC,前序遍历结果为ABDECF, 则后序遍历结果为 【 】 。
资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
前序遍历:若二叉树非空,则先访问根节点,再 遍历左子树,最后遍历右子树。
资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值
拓展:
已知二叉树的 后序遍历:D A B E C 中序遍历:D E B A C
请问前序遍历结果为?
资金是运动的价值,资金的价值是随 时间变 化而变 化的, 是时间 的函数 ,随时 间的推 移而增 值,其 增值的 这部分 资金就 是原有 资金的 时间价 值

二叉树基本操作经典实例

二叉树基本操作经典实例

二叉树基本操作经典实例二叉树是一种常见的数据结构,它由节点和指向左右子节点的指针组成。

二叉树的基本操作包括插入节点、删除节点、查找节点和遍历节点等。

在实际应用中,我们经常需要对二叉树进行基本操作,下面将介绍一些经典的例子。

一、插入节点插入节点是指向二叉树中添加一个新的节点。

在二叉树中插入节点的基本操作可以使用递归或者迭代的方法来实现。

下面是一个使用递归方法的示例代码:```public class TreeNodeint val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }public TreeNode insertNode(TreeNode root, int val)if (root == null)return new TreeNode(val);}if (val < root.val)root.left = insertNode(root.left, val);} else if (val > root.val)root.right = insertNode(root.right, val);}return root;```在上述代码中,通过递归的方式判断要插入的值和当前节点的大小关系,并将值插入到左子树或者右子树中,最后返回根节点。

二、删除节点删除节点是从二叉树中移除一个节点。

删除节点的基本操作可以分为三种情况:删除叶子节点、删除只有一个子节点的节点和删除有两个子节点的节点。

(1)删除叶子节点:如果要删除的节点是叶子节点,直接将该节点的父节点的指针指向空即可。

(2)删除只有一个子节点的节点:如果要删除的节点只有一个子节点,将该节点的子节点连接到该节点的父节点即可。

(3)删除有两个子节点的节点:如果要删除的节点有两个子节点,可以使用该节点右子树中的最小节点或者左子树中的最大节点来替代。

下面是一个使用递归方法的示例代码:```public TreeNode deleteNode(TreeNode root, int key) if (root == null)return root;}if (key < root.val)root.left = deleteNode(root.left, key);} else if (key > root.val)root.right = deleteNode(root.right, key);} elseif (root.left == null)return root.right;} else if (root.right == null)return root.left;}TreeNode minNode = findMin(root.right);root.val = minNode.val;root.right = deleteNode(root.right, minNode.val); }return root;private TreeNode findMin(TreeNode node)while (node.left != null)node = node.left;}return node;```在上述代码中,通过递归的方式判断要删除的值和当前节点的大小关系,并根据不同情况进行处理。

数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

数据结构与算法系列研究五——树、二叉树、三叉树、平衡排序二叉树AVL

数据结构与算法系列研究五——树、⼆叉树、三叉树、平衡排序⼆叉树AVL树、⼆叉树、三叉树、平衡排序⼆叉树AVL⼀、树的定义树是计算机算法最重要的⾮线性结构。

树中每个数据元素⾄多有⼀个直接前驱,但可以有多个直接后继。

树是⼀种以分⽀关系定义的层次结构。

a.树是n(≥0)结点组成的有限集合。

{N.沃恩}(树是n(n≥1)个结点组成的有限集合。

{D.E.Knuth})在任意⼀棵⾮空树中:⑴有且仅有⼀个没有前驱的结点----根(root)。

⑵当n>1时,其余结点有且仅有⼀个直接前驱。

⑶所有结点都可以有0个或多个后继。

b. 树是n(n≥0)个结点组成的有限集合。

在任意⼀棵⾮空树中:⑴有⼀个特定的称为根(root)的结点。

⑵当n>1时,其余结点分为m(m≥0)个互不相交的⼦集T1,T2,…,Tm。

每个集合本⾝⼜是⼀棵树,并且称为根的⼦树(subtree)树的固有特性---递归性。

即⾮空树是由若⼲棵⼦树组成,⽽⼦树⼜可以由若⼲棵更⼩的⼦树组成。

树的基本操作1、InitTree(&T) 初始化2、DestroyTree(&T) 撤消树3、CreatTree(&T,F) 按F的定义⽣成树4、ClearTree(&T) 清除5、TreeEmpty(T) 判树空6、TreeDepth(T) 求树的深度7、Root(T) 返回根结点8、Parent(T,x) 返回结点 x 的双亲9、Child(T,x,i) 返回结点 x 的第i 个孩⼦10、InsertChild(&T,&p,i,x) 把 x 插⼊到 P的第i棵⼦树处11、DeleteChild(&T,&p,i) 删除结点P的第i棵⼦树12、traverse(T) 遍历树的结点:包含⼀个数据元素及若⼲指向⼦树的分⽀。

●结点的度: 结点拥有⼦树的数⽬●叶结点: 度为零的结点●分枝结点: 度⾮零的结点●树的度: 树中各结点度的最⼤值●孩⼦: 树中某个结点的⼦树的根●双亲: 结点的直接前驱●兄弟: 同⼀双亲的孩⼦互称兄弟●祖先: 从根结点到某结点j 路径上的所有结点(不包括指定结点)。

详解平衡二叉树

详解平衡二叉树

一、平衡二叉树的概念平衡二叉树(Balanced binary tree)是由阿德尔森-维尔斯和兰迪斯(Adelson-Velskii and Landis)于1962年首先提出的,所以又称为AVL树。

定义:平衡二叉树或为空树,或为如下性质的二叉排序树:(1)左右子树深度之差的绝对值不超过1;(2)左右子树仍然为平衡二叉树.平衡因子BF=左子树深度-右子树深度.平衡二叉树每个结点的平衡因子只能是1,0,-1。

若其绝对值超过1,则该二叉排序树就是不平衡的。

如图所示为平衡树和非平衡树示意图:二、平衡二叉树算法思想若向平衡二叉树中插入一个新结点后破坏了平衡二叉树的平衡性。

首先要找出插入新结点后失去平衡的最小子树根结点的指针。

然后再调整这个子树中有关结点之间的链接关系,使之成为新的平衡子树。

当失去平衡的最小子树被调整为平衡子树后,原有其他所有不平衡子树无需调整,整个二叉排序树就又成为一棵平衡二叉树。

失去平衡的最小子树是指以离插入结点最近,且平衡因子绝对值大于1的结点作为根的子树。

假设用A表示失去平衡的最小子树的根结点,则调整该子树的操作可归纳为下列四种情况。

1)LL型平衡旋转法由于在A的左孩子B的左子树上插入结点F,使A的平衡因子由1增至2而失去平衡。

故需进行一次顺时针旋转操作。

即将A的左孩子B向右上旋转代替A作为根结点,A向右下旋转成为B的右子树的根结点。

而原来B的右子树则变成A的左子树。

(2)RR型平衡旋转法由于在A的右孩子C 的右子树上插入结点F,使A的平衡因子由-1减至-2而失去平衡。

故需进行一次逆时针旋转操作。

即将A的右孩子C向左上旋转代替A作为根结点,A向左下旋转成为C的左子树的根结点。

而原来C的左子树则变成A的右子树。

(3)LR型平衡旋转法由于在A的左孩子B的右子数上插入结点F,使A的平衡因子由1增至2而失去平衡。

故需进行两次旋转操作(先逆时针,后顺时针)。

即先将A结点的左孩子B的右子树的根结点D向左上旋转提升到B结点的位置,然后再把该D结点向右上旋转提升到A结点的位置。

平衡二叉树

平衡二叉树
2算法
编辑
红黑树
红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的,他称之为"对称二叉B树",它现代的名字是在 Leo J. Guibas 和 Robert Sedgewick 于1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n是树中元素的数目。
伸展树
伸展树(Splay Tree)是一种二叉排序树,它能在O(log n)内完成插入、查找和删除操作。它由Daniel Sleator和Robert Tarjan创造。它的优势在于不需要记录用于平衡树的冗余信息。在伸展树上的一般操作都基于伸展操作。
SBT
Size Balanced Tree(简称SBT)是一自平衡二叉查找树,是在计算机科学中用到的一种数据结构。它是由中国广东中山纪念中学的陈启峰发明的。陈启峰于2006年底完成论文《Size Balanced Tree》,并在2007年的全国青少年信息学奥林匹克竞赛冬令营中发表。由于SBT的拼写很容易找到中文谐音,它常被中国的信息学竞赛选手和ACM/ICPC选手们戏称为“傻B树”、“Super BT”等。相比红黑树、AVL树等自平衡二叉查找树,SBT更易于实现。据陈启峰在论文中称,SBT是“目前为止速度最快的高级二叉搜索树”。SBT能在O(log n)的时间内完成所有二叉搜索树(BST)的相关操作,而与普通二叉搜索树相比,SBT仅仅加入了简洁的核心操作Maintain。由于SBT赖以保持平衡的是size域而不是其他“无用”的域,它可以很方便地实现动态顺序统计中的select和rank操作。

数据结构:第9章 查找2-二叉树和平衡二叉树

数据结构:第9章 查找2-二叉树和平衡二叉树
NODE *t; char x; {if(t==NULL)
return(NULL); else
{if(t->data==x) return(t);
if(x<(t->data) return(search(t->lchild,x));
else return(search(t->lchild,x)); } }
——这种既查找又插入的过程称为动态查找。 二叉排序树既有类似于折半查找的特性,又采用了链表存储, 它是动态查找表的一种适宜表示。
注:若数据元素的输入顺序不同,则得到的二叉排序树形态 也不同!
讨论1:二叉排序树的插入和查找操作 例:输入待查找的关键字序列=(45,24,53,45,12,24,90)
二叉排序树的建立 对于已给定一待排序的数据序列,通常采用逐步插入结点的方 法来构造二叉排序树,即只要反复调用二叉排序树的插入算法 即可,算法描述为: BiTree *Creat (int n) //建立含有n个结点的二叉排序树 { BiTree *BST= NULL;
for ( int i=1; i<=n; i++) { scanf(“%d”,&x); //输入关键字序列
– 法2:令*s代替*p
将S的左子树成为S的双亲Q的右子树,用S取代p 。 若C无右子树,用C取代p。
例:请从下面的二叉排序树中删除结点P。
F P
法1:
F
P
C
PR
C
PR
CL Q
CL QL
Q SL
S PR
QL S
SL
法2:
F
PS
C
PR
CL Q
QL SL S SL

数据结构 -第12周查找第3讲-二叉排序树.pdf

数据结构 -第12周查找第3讲-二叉排序树.pdf

以二叉树或树作为表的组织形式,称为树表,它是一类动态查找表,不仅适合于数据查找,也适合于表插入和删除操作。

常见的树表:二叉排序树平衡二叉树B-树B+树9.3.1 二叉排序树二叉排序树(简称BST)又称二叉查找(搜索)树,其定义为:二叉排序树或者是空树,或者是满足如下性质(BST性质)的二叉树:❶若它的左子树非空,则左子树上所有节点值(指关键字值)均小于根节点值;❷若它的右子树非空,则右子树上所有节点值均大于根节点值;❸左、右子树本身又各是一棵二叉排序树。

注意:二叉排序树中没有相同关键字的节点。

二叉树结构满足BST性质:节点值约束二叉排序树503080209010854035252388例如:是二叉排序树。

66不试一试二叉排序树的中序遍历序列有什么特点?二叉排序树的节点类型如下:typedef struct node{KeyType key;//关键字项InfoType data;//其他数据域struct node*lchild,*rchild;//左右孩子指针}BSTNode;二叉排序树可看做是一个有序表,所以在二叉排序树上进行查找,和二分查找类似,也是一个逐步缩小查找范围的过程。

1、二叉排序树上的查找Nk< bt->keybtk> bt->key 每一层只和一个节点进行关键字比较!∧∧p查找到p所指节点若k<p->data,并且p->lchild=NULL,查找失败。

若k>p->data,并且p->rchild=NULL,查找失败。

查找失败的情况加上外部节点一个外部节点对应某内部节点的一个NULL指针递归查找算法SearchBST()如下(在二叉排序树bt上查找关键字为k的记录,成功时返回该节点指针,否则返回NULL):BSTNode*SearchBST(BSTNode*bt,KeyType k){if(bt==NULL||bt->key==k)//递归出口return bt;if(k<bt->key)return SearchBST(bt->lchild,k);//在左子树中递归查找elsereturn SearchBST(bt->rchild,k);//在右子树中递归查找}在二叉排序树中插入一个关键字为k的新节点,要保证插入后仍满足BST性质。

数据结构:二叉树、平衡二叉树、红黑树详解

数据结构:二叉树、平衡二叉树、红黑树详解

数据结构:⼆叉树、平衡⼆叉树、红⿊树详解⼀、⼆叉树(binary tree)指每个节点最多含有两个⼦树的树结构。

时间复杂度为O(log N),在退化成链表的情况下时间复杂度为O(N)。

特点:1.所有节点最多拥有两个⼦节点;2.节点的左⼦树只包含⼩于当前根节点的数,节点的右⼦树只包含⼤于当前根节点的数。

缺点:只会以我们第⼀次添加的节点为根节点,如果后⾯添加的节点值都⼤于或⼩于根节点的值,在这种情况下会退化成链表。

⼆、平衡⼆叉树(Balanced Binary Tree)⼜称为AVL树,具有⼆叉树的全部特性,解决⼆叉树退化成链表情况的问题,每个节点的左⼦树和右⼦树的⾼度之差不会超过1,AVL树是严格的平衡⼆叉树,追求完全平衡,⽐较严格。

缺点:由于要求每个节点的左⼦树和右⼦树⾼度之差不超过1,这个要求⾮常严格,追求完全平衡,这就导致了在频繁插⼊和删除的场景中,可能就会导致AVL树失去平衡,AVL树就需要频繁的通过左旋右旋使其重新达到平衡,这时就会时得其性能⼤打折扣。

三、红⿊树和AVL树相⽐,红⿊树放弃追求完全平衡,⽽是追求⼤致平衡,保证每次插⼊节点最多只需要三次旋转就能达到平衡,维持平衡的耗时较少,实现起来也更为简单,它的旋转次数较少,对于频繁插⼊和删除操作的场景,相⽐AVL树,红⿊树更具优势。

特征:1.红⿊树是也是平衡⼆叉树实现的⼀种⽅式2.节点只能是⿊⾊或者红⾊,root根节点⼀定是⿊⾊3.新增时默认新增的节点是红⾊,不允许两个红⾊节点相连4.红⾊节点的两个⼦节点⼀定是⿊⾊红⿊树变换规则三种规则:1.改变节点颜⾊2.左旋转3.右旋转变⾊的情况:当前节点的⽗亲节点是红⾊,并且它的祖⽗节点的另外⼀个⼦节点(叔叔节点)也是红⾊:以当前节点为指针进⾏操作1.将⽗亲节点变为⿊⾊2.将叔叔节点变为⿊⾊3.将祖⽗节点变为红⾊4.再把指针定义到祖⽗节点进⾏旋转操作左旋转:当⽗亲节点为红⾊情况,叔叔节点为⿊⾊情况,且当前节点是右⼦树,左旋转以⽗节点作为左旋。

平衡二叉树详解

平衡二叉树详解

平衡⼆叉树详解平衡⼆叉树详解简介平衡⼆叉树(Balanced Binary Tree)具有以下性质:它是⼀棵空树或它的左右两个⼦树的⾼度差的绝对值不超过1,并且左右两个⼦树都是⼀棵平衡⼆叉树。

平衡⼆叉树的常⽤实现⽅法有红⿊树、AVL、替罪⽺树、Treap、伸展树等。

其中最为经典当属AVL树,我们总计⽽⾔就是:平衡⼆叉树是⼀种⼆叉排序树,其中每⼀个结点的左⼦树和右⼦树的⾼度差⾄多等于1。

性值AVL树具有下列性质的⼆叉树(注意,空树也属于⼀种平衡⼆叉树):l 它必须是⼀颗⼆叉查找树l 它的左⼦树和右⼦树都是平衡⼆叉树,且左⼦树和右⼦树的深度之差的绝对值不超过1。

l 若将⼆叉树节点的平衡因⼦BF定义为该节点的左⼦树的深度减去它的右⼦树的深度,则平衡⼆叉树上所有节点的平衡因⼦只可能为-1,0,1.l 只要⼆叉树上有⼀个节点的平衡因⼦的绝对值⼤于1,那么这颗平衡⼆叉树就失去了平衡。

实现平衡⼆叉树不平衡的情形:把需要重新平衡的结点叫做α,由于任意两个结点最多只有两个⼉⼦,因此⾼度不平衡时,α结点的两颗⼦树的⾼度相差2.容易看出,这种不平衡可能出现在下⾯4中情况中:1.对α的左⼉⼦的左⼦树进⾏⼀次插⼊2.对α的左⼉⼦的右⼦树进⾏⼀次插⼊3.对α的右⼉⼦的左⼦树进⾏⼀次插⼊4.对α的右⼉⼦的右⼦树进⾏⼀次插⼊(1)LR型(2)LL型(3)RR型(4)RL型完整代码#include<stdio.h>#include<stdlib.h>//结点设计typedef struct Node {int key;struct Node *left;struct Node *right;int height;} BTNode;int height(struct Node *N) {if (N == NULL)return0;return N->height;}int max(int a, int b) {return (a > b) ? a : b;}BTNode* newNode(int key) {struct Node* node = (BTNode*)malloc(sizeof(struct Node));node->key = key;node->left = NULL;node->right = NULL;node->height = 1;return(node);}//ll型调整BTNode* ll_rotate(BTNode* y) {BTNode *x = y->left;y->left = x->right;x->right = y;y->height = max(height(y->left), height(y->right)) + 1;x->height = max(height(x->left), height(x->right)) + 1;return x;}//rr型调整BTNode* rr_rotate(BTNode* y) {BTNode *x = y->right;y->right = x->left;x->left = y;y->height = max(height(y->left), height(y->right)) + 1;x->height = max(height(x->left), height(x->right)) + 1;return x;}//判断平衡int getBalance(BTNode* N) {if (N == NULL)return0;return height(N->left) - height(N->right);}//插⼊结点&数据BTNode* insert(BTNode* node, int key) {if (node == NULL)return newNode(key);if (key < node->key)node->left = insert(node->left, key);else if (key > node->key)node->right = insert(node->right, key);elsereturn node;node->height = 1 + max(height(node->left), height(node->right)); int balance = getBalance(node);if (balance > 1 && key < node->left->key) //LL型return ll_rotate(node);if (balance < -1 && key > node->right->key) //RR型return rr_rotate(node);if (balance > 1 && key > node->left->key) { //LR型node->left = rr_rotate(node->left);return ll_rotate(node);}if (balance < -1 && key < node->right->key) { //RL型node->right = ll_rotate(node->right);return rr_rotate(node);return node;}//遍历void preOrder(struct Node *root) { if (root != NULL) {printf("%d ", root->key);preOrder(root->left);preOrder(root->right);}}int main() {BTNode *root = NULL;root = insert(root, 2);root = insert(root, 1);root = insert(root, 0);root = insert(root, 3);root = insert(root, 4);root = insert(root, 4);root = insert(root, 5);root = insert(root, 6);root = insert(root, 9);root = insert(root, 8);root = insert(root, 7);printf("前序遍历:");preOrder(root);return0;}。

数据结构清华大学殷人昆演示文稿

数据结构清华大学殷人昆演示文稿

则递归到只有一个结点的子树。 树的子树棵数不限,而N叉树中根的子树最多N
棵。
树可以区分为外向树和内向树,而N叉树一般是外向
树,即边是有向的,从父指向子。
树可以用N叉树实现。二叉树、B树等又都是N叉
树的特殊情形。
第六页,共二百零一页。
树的特点
数据结构清华大学殷人 昆演示文稿
1
第一页,共二百零一页。
数据结构清华大学殷人 昆
2
第二页,共二百零一页。
第 4 章 树与二叉树
树的定义与基本概念
二叉树 二叉树遍历 二叉树的计数 线索二叉树
树与树的遍历
树的应用
第三页,共二百零一页。
树和森林的概念
树的定义
树是由n (n>0) 个结点组成的有限集合: ➢ 有一个特定的称之为根(root)的结点; ➢ 除根以外的其它结点划分为 m (m≥0) 个 互 不相交的有限集合T1, T2, …, Tm,每个集合又 是一棵树,并且称之为根的子树。
第十四页,共二百零一页。
性质4 具有 n (n≥0) 个结点的完全二叉树的高度为 log2(n+1)
证明:设完全二叉树的高度为 h,则有 2h-1-1<n ≤ 2h-1
上面h-1层结点数 包括第h层的最大结点数
变形 2h-1<n+1≤2h
取对数
h-1<log2(n+1)≤h 有 h = log2(n+1)
树是分层结构,又是递归结构。每棵子树的根结点有 且仅有一个直接前驱,但可以有 0 个或多个直接后继。
前驱
A
B
后继 E F
C
D
GHI J
KL
M
1层 2层
depth = 4 3层 height= 4 4层

算法(平衡二叉树)

算法(平衡二叉树)

算法(平衡⼆叉树)科普⼆叉树⼆叉树⼆叉数是每个节点最多有两个⼦树,或者是空树(n=0),或者是由⼀个根节点及两个互不相交的,分别称为左⼦树和右⼦树的⼆叉树组成满⼆叉树有两个⾮空⼦树(⼆叉树中的每个结点恰好有两个孩⼦结点切所有叶⼦结点都在同⼀层)也就是⼀个结点要么是叶结点,要么是有两个⼦结点的中间结点。

深度为k且含有2^k-1个结点的⼆叉树完全⼆叉树从左到右依次填充从根结点开始,依次从左到右填充树结点。

除最后⼀层外,每⼀层上的所有节点都有两个⼦节点,最后⼀层都是叶⼦节点。

平衡⼆叉树AVL树[3,1,2,5,9,7]⾸先科普下⼆叉排序树⼜称⼆叉查找树,议程⼆叉搜索树⼆叉排序树的规则⽐本⾝⼤放右边,⽐本⾝⼩放左边平衡⼆叉数⾸先是⼀个⼆叉排序树左右两个⼦树的⾼度差不⼤于1下⾯图中是平衡的情况下⾯是不平衡的情况引⼊公式(LL)右旋function toateRight(AvlNode){let node=AvlNode.left;//保存左节点 AvlNode.left=node.right;node.right=AvlNode;}(RR)左旋function roateLeft(AvlNode){let node=AvlNode.right;//保存右⼦节点AvlNode.right=node.left;node.left=AvlNode;return node;}左右旋⼤图判断⼆叉树是不是平衡树⼆叉树任意结点的左右⼦树的深度不超过1深度计算定义⼀个初始化的⼆叉树var nodes = {node: 6,left: {node: 5,left: {node: 4},right: {node: 3}},right: {node: 2,right: {node: 1}}}//计算⾼度const treeDepth = (root) => {if (root == null) {return 0;}let left = treeDepth(root.left)let right = treeDepth(root.right)return 1+(left>right?left:right)}//判断深度const isTree=(root)=>{if (root == null) {return true;}let left=treeDepth(root.left)let right=treeDepth(root.right)let diff=left-right;if (diff > 1 || diff < -1) {return false}return isTree(root.left)&&isTree(root.right) }console.log(isTree(nodes))判断⼆叉数是不是搜索⼆叉树//第⼀种 //中序遍历let last=-Infinity;const isValidBST=(root)=>{if (root == null) {return true;}//先从左节点开始if (isValidBST(root.left)) {if (last < root.node) {last=root.node;return isValidBST(root.right)}}return false}console.log(isValidBST(nodes))//第⼆种const isValidBST = root => {if (root == null) {return true}return dfs(root, -Infinity, Infinity)}const dfs = (root, min, max) => {if (root == null) {return true}if (root.node <= min || root.node >= max) {return false}return dfs(root.left, min, root.node) && dfs(root.right, root.node, max)}console.log(isValidBST(nodes))实现⼀个⼆叉树实现了⼆叉树的添加,删除,查找,排序//⼆叉树结点class TreeNode {constructor(n, left, right){this.n = n;this.left = left;this.right = right;}}//⼆叉树class BinaryTree {constructor(){this.length = 0;this.root = null;this.arr = [];}//添加对外⼊⼝,⾸个参数是数组,要求数组⾥都是数字,如果有不是数字则试图转成数字,如果有任何⼀个⽆法强制转成数字,则本操作⽆效 addNode(){let arr = arguments[0];if(arr.length == 0) return false;return this.judgeData('_addNode', arr)}//删除结点deleteNode(){let arr = arguments[0];if(arr.length == 0) return false;return this.judgeData('_deleteNode', arr)}//传值判断,如果全部正确,则全部加⼊叉树judgeData(func, arr){let flag = false;//任何⼀个⽆法转成数字,都会失败if(arr.every(n => !Number.isNaN(n))){let _this = this;arr.map(n => _this[func](n));flag = true;}return flag;}//添加的真实实现_addNode(n){n = Number(n);let current = this.root;let treeNode = new TreeNode(n, null, null);if(this.root === null){this.root = treeNode;}else {current = this.root;while(current){let parent = current;if(n < current.n){current = current.left;if(current === null){parent.left = treeNode;}}else {current = current.right;if(current === null){parent.right = treeNode;}}}}this.length++;return treeNode;}//删除节点的真实实现_deleteNode(n){n = Number(n);if(this.root === null){return;}//查找该节点,删除节点操作⽐较复杂,为排除找不到被删除的节点的情况,简化代码,先保证该节点是存在的,虽然这样做其实重复了⼀次查询了,但⼆叉树的查找效率很⾼,这是可接受的let deleteNode = this.findNode(n);if(!deleteNode){return;}//如果删除的是根节点if(deleteNode === this.root){if(this.root.left === null && this.root.right === null){this.root = null;}else if(this.root.left === null){this.root = this.root.right;}else if(this.root.right === null){this.root = this.root.left;}else {let [replaceNode, replacePNode, rp] = this.findLeftTreeMax(deleteNode);replacePNode[rp] = null;replaceNode.left = this.root.left;replaceNode.right = this.root.right;this.root = replaceNode;}}else {//被删除的⽗节点,⼦节点在⽗节点的位置p,有left,right两种可能let [deleteParent, p] = this.findParentNode(deleteNode);if(deleteNode.left === null && deleteNode.right === null){deleteParent[p] = null;}else if(deleteNode.left === null){deleteParent[p] = deleteNode.right;}else if(deleteNode.right === null){deleteParent[p] = deleteNode.left;}else {//⽤来替换被删除的节点,⽗节点,节点在⽗节点的位置let [replaceNode, replacePNode, rp] = this.findLeftTreeMax(deleteNode);if(replacePNode === deleteNode){deleteParent[p] = replaceNode;}else {deleteParent[p] = replaceNode;replacePNode.right = null;}replacePNode[rp] = null;replaceNode.left = deleteNode.left;replaceNode.right = deleteNode.right;}}this.length--;}//查找findNode(n){let result = null;let current = this.root;while(current){if(n === current.n){result = current;break;}else if(n < current.n){current = current.left;}else {current = current.right;}}return result;}//查找⽗节点findParentNode(node){let [parent, child, p] = [null, null, null];if(this.root !== node){parent = this.root;if(node.n < parent.n){child = parent.left;p = 'left';}else {child = parent.right;p = 'right';}while(child){if(node.n === child.n){break;}else if(node.n < child.n){parent = child;child = parent.left;p = 'left';}else {parent = child;child = parent.right;p = 'right';}}}return [parent, p];}//查找当前有左⼦树的节点的最⼤值的节点M,如有A个节点被删除,M是最接近A点之⼀(还有⼀个是右⼦树节点的最⼩值) findLeftTreeMax(topNode){let [node, parent, p] = [null, null, null];if(this.root === null || topNode.left === null){return [node, parent, p];}parent = topNode;node = topNode.left;p = 'left';while(node.right){parent = node;node = node.right;p = 'right';}return [node, parent, p];}//查找最⼤值maxValue(){if(this.root !== null){return this._findLimit('right');}}//查找最⼩值minValue(){if(this.root !== null){return this._findLimit('left');}}//实现查找特殊值_findLimit(pro){let n = this.root.n;let current = this.root;while(current[pro]){current = current[pro];n = current.n;}return n;}//中序排序,并⽤数组的形式显⽰sortMiddleToArr(){this._sortMiddleToArr(this.root);return this.arr;}//中序⽅法_sortMiddleToArr(node){if(node !== null){this._sortMiddleToArr(node.left);this.arr.push(node.n);this._sortMiddleToArr(node.right);}}//打印⼆叉树对象printNode(){console.log(JSON.parse(JSON.stringify(this.root)));}}//测试var binaryTree = new BinaryTree();binaryTree.addNode([50, 24, 18, 65, 4, 80, 75, 20, 37, 40, 60]);binaryTree.printNode();//{n: 50, left: {…}, right: {…}}console.log(binaryTree.maxValue());//80console.log(binaryTree.minValue());//4console.log(binaryTree.sortMiddleToArr());// [4, 18, 20, 24, 37, 40, 50, 60, 65, 75, 80] binaryTree.deleteNode([50]);binaryTree.printNode();//{n: 40, left: {…}, right: {…}}排序复习function ArrayList() {this.array = [];}ArrayList.prototype = {constructor: ArrayList,insert: function(item) {this.array.push(item);},toString: function() {return this.array.join();},swap: function(index1, index2) {var aux = this.array[index2];this.array[index2] = this.array[index1];this.array[index1] = aux;},//冒泡排序bubbleSort: function() {var length = this.array.length;for (var i = 0; i < length; i++) {for (var j = 0; j < length - 1 - i; j++) {if (this.array[j] > this.array[j + 1]) {this.swap(j, j + 1);}}}},//选择排序selectionSort: function() {var length = this.array.length;var indexMin;for (var i = 0; i < length - 1; i++) {indexMin = i;for (var j = i; j < length; j++) {if (this.array[indexMin] > this.array[j]) {indexMin = j;}}if (indexMin !== i) {this.swap(indexMin, i);}}},//插⼊排序insertionSort: function() {var length = this.array.length;var j;var temp;for (var i = 1; i < length; i++) {temp = this.array[i];j = i;while (j > 0 && this.array[j - 1] > temp) {this.array[j] = this.array[j - 1];j--;}this.array[j] = temp;}},//归并排序mergeSort: function() {function mergeSortRec(array) {var length = array.length;if (length === 1) {return array;}var mid = Math.floor(length / 2);var left = array.slice(0, mid);var right = array.slice(mid, length);return merge(mergeSortRec(left), mergeSortRec(right)); }function merge(left, right) {var result = [];var il = 0;var ir = 0;while (il < left.length && ir < right.length) {if (left[il] < right[ir]) {result.push(left[il++]);} else {result.push(right[ir++]);}}while (il < left.length) {result.push(left[il++]);}while (ir < right.length) {result.push(right[ir++]);}return result;}this.array = mergeSortRec(this.array);},//快速排序quickSort:function(){function sort(array){if (array.length <= 1) {return array;}var pivotIndex = Math.floor(array.length/2);var pivot = array.splice(pivotIndex,1)[0];var left = [];var right = [];for(var i = 0; i < array.length; i++){if (array[i] < pivot) {left.push(array[i]);}else{right.push(array[i]);}}return sort(left).concat([pivot],sort(right));}this.array = sort(this.array);}};...................................................................................................................############################################################################ ###################################################################################。

平衡二叉树构造过程

平衡二叉树构造过程

平衡二叉树构造过程1.插入操作:插入新节点是平衡二叉树构造过程中的基本操作之一、首先,将新节点插入到二叉树中的合适位置,然后检查树的平衡性。

在插入过程中,需要更新每个节点的高度,并验证是否需要进行旋转操作,以保持树的平衡。

具体插入操作的步骤如下:1.1在树中查找合适的位置插入新节点,按照二叉树的规则:-如果新节点值小于当前节点值,则继续在当前节点的左子树中查找合适位置插入新节点;-如果新节点值大于当前节点值,则继续在当前节点的右子树中查找合适位置插入新节点;-如果当前节点为空,则将新节点插入到此位置。

1.2更新每个节点的高度,从插入的节点开始,向上遍历到根节点。

计算每个节点的左子树高度和右子树高度,然后取其中较大值加1作为节点的新高度。

1.3验证平衡性。

对于每个节点,计算其左右子树高度差的绝对值,如果超过1,则需要进行旋转操作。

2.旋转操作:旋转是平衡二叉树构造过程中的关键步骤,用来调整树的结构,使其保持平衡。

2.1左旋:将当前节点的右子树变为新的根节点,当前节点成为新的根节点的左子树,新的根节点的左子树成为当前节点的右子树。

2.2右旋:将当前节点的左子树变为新的根节点,当前节点成为新的根节点的右子树,新的根节点的右子树成为当前节点的左子树。

2.3左右旋:先对当前节点的左子树进行左旋操作,然后再对当前节点进行右旋操作。

2.4右左旋:先对当前节点的右子树进行右旋操作,然后再对当前节点进行左旋操作。

旋转操作的目的是调整树的结构,使得左右子树的高度差不超过1,并保持二叉树的性质。

3.删除操作:删除节点是平衡二叉树构造过程中的另一个重要操作。

删除操作也需要更新树的高度和进行旋转操作。

删除操作的步骤如下:3.1在树中查找要删除的节点。

如果要删除的节点是叶子节点,则直接删除即可。

3.2如果要删除的节点只有一个子节点,则将子节点替换成当前节点的位置。

3.3如果要删除的节点有两个子节点,则找到当前节点的后继节点(即比当前节点大的最小节点)或前驱节点(即比当前节点小的最大节点),将后继节点或前驱节点的值复制到当前节点,并删除后继节点或前驱节点。

数据结构_第9章_查找2-二叉树和平衡二叉树

数据结构_第9章_查找2-二叉树和平衡二叉树

F
PS
C
PR
CL Q
QL SL S SL
10
3
18
2
6 12
6 删除10
3
18
2
4 12
4
15
15
三、二叉排序树的查找分析
1) 二叉排序树上查找某关键字等于给定值的结点过程,其实 就是走了一条从根到该结点的路径。 比较的关键字次数=此结点的层次数; 最多的比较次数=树的深度(或高度),即 log2 n+1
-0 1 24
0 37
0 37
-0 1
需要RL平衡旋转 (绕C先顺后逆)
24
0
-012
13
3573
0
01
37
90
0 53 0 53
0 90
作业
已知如下所示长度为12的表:
(Jan, Feb, Mar, Apr, May, June, July, Aug, Sep, Oct, Nov, Dec)
(1) 试按表中元素的顺序依次插入一棵初始为空的二叉 排序树,画出插入完成之后的二叉排序树,并求其在 等概率的情况下查找成功的平均查找长度。
2) 一棵二叉排序树的平均查找长度为:
n i1
ASL 1
ni Ci
m
其中:
ni 是每层结点个数; Ci 是结点所在层次数; m 为树深。
最坏情况:即插入的n个元素从一开始就有序, ——变成单支树的形态!
此时树的深度为n ; ASL= (n+1)/2 此时查找效率与顺序查找情况相同。
最好情况:即:与折半查找中的判ห้องสมุดไป่ตู้树相同(形态比较均衡) 树的深度为:log 2n +1 ; ASL=log 2(n+1) –1 ;与折半查找相同。

平衡二叉树的调整方法

平衡二叉树的调整方法

平衡二叉树的调整方法
平衡二叉树是一种具有左右子树高度差不超过1的二叉树结构。

但是在实际应用中,由于插入、删除等操作会导致树的不平衡,所以需要对二叉树进行调整以保持平衡。

常见的平衡二叉树调整方法包括AVL树和红黑树。

AVL树是一种严格的平衡二叉树,它通过旋转操作来调整树的平衡性。

AVL树的调整过程需要通过计算节点的平衡因子(左右子树高度差)来确定需要进行的旋转操作,具体包括左旋、右旋、左右旋和右左旋四种操作。

这些旋转操作可以通过改变节点的指针关系来调整树的平衡,保持树的高度平衡性。

红黑树是一种近似平衡的二叉搜索树,它通过染色和旋转操作来调整树的平衡性。

红黑树的调整过程相对于AVL树来说更加简单,具有较低的调整成本。

红黑树的特点是每个节点有一个颜色属性(红色或黑色),并且满足以下四个条件:1. 根节点是黑色;2. 所有叶子节点(NIL节点)是黑色;3. 任意两个相邻节点不能同时为红色;4. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。

通过对节点的染色和旋转操作,红黑树可以保持树的平衡性。

除了AVL树和红黑树,还有其他一些平衡二叉树的调整方法,如Treap树、Splay 树等。

这些方法在特定场景下可以提供更好的性能,但它们的实现复杂度较高,适用性有一定的限制。

总而言之,平衡二叉树的调整方法是为了保持树的平衡性,以提高树的查询和插入等操作的效率。

不同的调整方法适用于不同的应用场景,根据实际需求选择合适的平衡二叉树调整方法是非常重要的。

广工数据结构实验报告平衡二叉树

广工数据结构实验报告平衡二叉树

数据结构实验报告题目:平衡二叉树学院专业年级班别学号学生姓名指导教师2015年7月1日1.题目:采用字符类型为整型类型和链式存储结构,实现抽象数据类型BTree。

ADT BTree{数据对象:D={a i | a i∈ElemSet,i=1,2,。

.。

,n,n≥0 }数据关系:R1={<a i—1,a i>|a i—1, a i∈D, i=2,。

.,n }基本操作:Adj_balance(T)操作结果:创建平衡二叉树。

InsertA VL(T,search,taller)初始条件:二叉树T已存在。

操作结果:增加新结点。

SetA VL(T,search,taller)初始条件:二叉树T已存在。

操作结果:在平衡二叉树上增加新结点并调平衡.DeleteA VL(T,search,shorter)初始条件:二叉树T已存在.操作结果:删除结点。

}ADT BTree2.存储结构定义公用头文件DS0。

h:#include〈stdio。

h〉#include 〈malloc.h>树的内部变量typedef struct BTNode{int data;int bf; //平衡因子struct BTNode *lchild,*rchild;//左、右孩子}BTNode,*BTree;/*需要的函数声明*/void Right_Balance(BTree &p);void Left_Balance(BTree &p);void Left_Root_Balance(BTree &T);void Right_Root_Balance(BTree &T);bool InsertA VL(BTree &T,int i,bool &taller);void PrintBT(BTree T);void Left_Root_Balance_det(BTree &p,int &shorter);void Right_Root_Balance_det(BTree &p,int &shorter);void Delete(BTree q,BTree &r,int &shorter);int DeleteA VL(BTree &p,int x,int &shorter);void Adj_balance(BTree &T);bool SetA VL(BTree &T,int i,bool &taller);bool Insert_Balance_A VL(BTree &T,int i,bool &taller);int menu();3.算法设计/*对以*p为根的二叉排序树作右旋处理*/void Right_Balance(BTree &p){BTree lc;lc =p-〉lchild;//lc指向的*p左子树根结点p->lchild = lc-〉rchild;//rc的右子树挂接为*p的左子树lc—〉rchild = p;p = lc; //p指向新的结点}/*对以*p为根的二叉排序树作左旋处理*/void Left_Balance(BTree &p){BTree rc;rc = p-〉rchild;//指向的*p右子树根结点p—〉rchild = rc—〉lchild;//rc左子树挂接到*p的右子树rc->lchild = p;p = rc; //p指向新的结点}/*对以指针T所指结点为根的二叉树作左平衡旋转处理*/void Left_Root_Balance(BTree &T){BTree lc,rd;lc = T-〉lchild;//指向*T的左子树根结点switch(lc->bf)//检查*T的左子树的平衡度,并作相应平衡处理{case 1://新结点插入在*T的左孩子的左子树上,要作单右旋处理T—〉bf = lc—>bf = 0;Right_Balance(T);break;case -1://新结点插入在*T的左孩子的右子树上,要作双旋处理rd = lc—〉rchild; //rd指向*T的左孩子的右子树根switch(rd-〉bf)//修改*T及其左孩子的平衡因子{case 1:T-〉bf = -1;lc—>bf = 0;break;case 0:T->bf = lc—>bf = 0;break;case —1:T-〉bf = 0;lc—〉bf = 1;break;}rd—〉bf = 0;Left_Balance(T->lchild); //对*T的左子树作左旋平衡处理Right_Balance(T);//对*T作右旋平衡处理}}/*对以指针T所指结点为根的二叉树作右平衡旋转处理*/void Right_Root_Balance(BTree &T){BTree rc,ld;rc = T—>rchild;//指向*T的左子树根结点switch(rc—〉bf)//检查*T的右子树的平衡度,并作相应平衡处理{case -1://新结点插入在*T的右孩子的右子树上,要作单左旋处理T-〉bf = rc-〉bf =0;Left_Balance(T);break;case 1://新结点插入在*T的右孩子的左子树上,要作双旋处理ld = rc—〉lchild; //ld指向*T的右孩子的左子树根switch(ld—>bf)//修改*T及其右孩子的平衡因子{case 1:T->bf = 0;rc—>bf = -1;break;case 0:T—>bf = rc->bf =0;break;case -1:T—>bf = 1;rc—>bf = 0;break;}ld—〉bf = 0;Right_Balance(T-〉rchild);//对*T的右子树作左旋平衡处理Left_Balance(T); //对*T作左旋平衡处理}}/*插入结点i,若T中存在和i相同关键字的结点,则插入一个数据元素为i的新结点,并返回1,否则返回0*/bool InsertA VL(BTree &T,int i,bool &taller){if(!T)//插入新结点,树“长高”,置taller为true{T = (BTree)malloc(sizeof(BTNode));T-〉data = i;T—>lchild = T—>rchild =NULL;T-〉bf = 0;taller = true;}else{if(i==T—〉data) //树中已存在和有相同关键字的结点{taller = 0;printf("已存在相同关键字的结点\n”);return 0;}if(i〈T—〉data) //应继续在*T的左子树中进行搜索{if(!InsertA VL(T->lchild,i,taller))return 0;}else //应继续在*T的右子树中进行搜索{if(!InsertA VL(T—〉rchild,i,taller))return 0;}}return 1;}/*输出二叉树*/void PrintBT(BTree T){if(T){printf(”%d",T->data);if(T-〉lchild||T-〉rchild){printf("(");PrintBT(T—〉lchild);printf(",”);PrintBT(T->rchild);printf(”)”);}}}/*删除结点时左平衡旋转处理*/void Left_Root_Balance_det(BTree &p,int &shorter){BTree p1,p2;if(p->bf==1)//p结点的左子树高,删除结点后p的bf减,树变矮{p—>bf=0;shorter=1;}else if(p->bf==0)//p结点左、右子树等高,删除结点后p的bf减,树高不变{p-〉bf=—1;shorter=0;}else //p结点的右子树高{p1=p—>rchild;//p1指向p的右子树if(p1—〉bf==0)//p1结点左、右子树等高,删除结点后p的bf为—2,进行左旋处理,树高不变{Left_Balance(p);p1—>bf=1;p-〉bf=-1;shorter=0;}else if(p1-〉bf==-1)//p1的右子树高,左旋处理后,树变矮{Left_Balance(p);p1—〉bf=p—>bf=0;shorter=1;}else //p1的左子树高,进行双旋处理(先右旋后左旋),树变矮{p2=p1—〉lchild;p1—〉lchild=p2—>rchild;p2—〉rchild=p1;p—>rchild=p2-〉lchild;p2—>lchild=p;if(p2—〉bf==0){p->bf=0;p1—>bf=0;}else if(p2-〉bf==—1){p-〉bf=1;p1—>bf=0;}else{p-〉bf=0;p1—>bf=—1;}p2-〉bf=0;p=p2;shorter=1;}}}/*删除结点时右平衡旋转处理*/void Right_Root_Balance_det(BTree &p,int &shorter){BTree p1,p2;if(p-〉bf==-1){p->bf=0;shorter=1;}else if(p-〉bf==0){p—>bf=1;shorter=0;}else{p1=p->lchild;if(p1—〉bf==0){Right_Balance(p);p1—>bf=—1;p—>bf=1;shorter=0;}else if(p1->bf==1){Right_Balance(p);p1->bf=p—>bf=0;shorter=1;}else{p2=p1—>rchild;p1—〉rchild=p2—〉lchild;p2-〉lchild=p1;p->lchild=p2—>rchild;p2->rchild=p;if(p2-〉bf==0){p—〉bf=0;p1->bf=0;}else if(p2-〉bf==1){p—〉bf=—1;p1—>bf=0;}else{p-〉bf=0;p1->bf=1;}p2->bf=0;p=p2;shorter=1;}}}/*删除结点*/void Delete(BTree q,BTree &r,int &shorter) {if(r-〉rchild==NULL){q—〉data=r->data;q=r;r=r—>lchild;free(q);shorter=1;}else{Delete(q,r—>rchild,shorter);if(shorter==1)Right_Root_Balance_det(r,shorter);}}/*二叉树的删除操作*/int DeleteA VL(BTree &p,int x,int &shorter){int k;BTree q;if(p==NULL){printf("不存在要删除的关键字!!\n");return 0;}else if(x<p-〉data)//在p的左子树中进行删除{k=DeleteA VL(p-〉lchild,x,shorter);if(shorter==1)Left_Root_Balance_det(p,shorter);return k;}else if(x>p->data)//在p的右子树中进行删除{k=DeleteA VL(p—>rchild,x,shorter);if(shorter==1)Right_Root_Balance_det(p,shorter);return k;}else{q=p;if(p->rchild==NULL)//右子树空则只需重接它的左子树{p=p—>lchild;free(q);shorter=1;}else if(p->lchild==NULL)//左子树空则只需重接它的右子树{p=p—>rchild;free(q);shorter=1;}else//左右子树均不空{Delete(q,q->lchild,shorter);if(shorter==1)Left_Root_Balance_det(p,shorter);p=q;}return 1;}}/*调平二叉树具体方法*/bool SetA VL(BTree &T,int i,bool &taller){if(!T)//插入新结点,树“长高”,置taller为true{T = (BTree)malloc(sizeof(BTNode));T-〉data = i;T—〉lchild = T—〉rchild =NULL;T—>bf = 0;taller = true;}else{if(i==T-〉data) //树中已存在和有相同关键字的结点{taller = false;printf("已存在相同关键字的结点\n”);return 0;}if(i〈T—〉data)//应继续在*T的左子树中进行搜索{if(!SetA VL(T->lchild,i,taller))return 0;if(taller) //已插入到*T的左子树中且左子树“长高”switch(T—>bf)//检查*T的平衡度{case 1://原本左子树比右子树高,需要作左平衡处理Left_Root_Balance(T);taller = false;break;case 0: //原本左子树、右子等高,现因左子树增高而使树增高T->bf = 1;taller = true;break;case -1: //原本右子树比左子树高,现左、右子树等高T—〉bf = 0;taller = false;break;}}else //应继续在*T的右子树中进行搜索{if(!SetA VL(T—〉rchild,i,taller))return 0;if(taller) //已插入到*T的右子树中且右子树“长高”switch(T-〉bf)//检查*T的平衡度{case 1://原本左子树比右子树高,现左、右子树等高T-〉bf = 0;taller = false;break;case 0: //原本左子树、右子等高,现因右子树增高而使树增高T-〉bf = -1;taller = true;break;case —1://原本右子树比左子树高,需要作右平衡处理Right_Root_Balance(T);taller = false;break;}}return 1;}}/*二叉树调平操作*/void Adj_balance(BTree &T){int i;bool taller=false;T = NULL;printf(”\n请输入关键字(以—1结束建立平衡二叉树):");scanf("%d",&i);getchar();while(i != -1){SetA VL(T,i,taller);printf("\n请输入关键字(以-1结束建立平衡二叉树):”);scanf(”%d",&i);getchar();taller=false;}printf("平衡二叉树创建结束。

平衡二叉树构造方法

平衡二叉树构造方法

平衡二叉树构造方法构造平衡二叉树的方法有很多,其中一种绝妙的方法是通过AVL树进行构造。

AVL树是一种平衡二叉树,它的左子树和右子树的高度差不超过1、利用这种特性,我们可以通过以下步骤构造平衡二叉树:1.将需要构造平衡二叉树的数据按照升序或者降序排列。

2.选择数据的中间元素作为根节点。

3.将数据分成左右两个部分,分别作为根节点的左子树和右子树的数据。

4.递归地对左子树和右子树进行构造。

下面我们通过一个例子来具体说明这个方法:假设我们需要构造一个平衡二叉树,并且数据为1,2,3,4,5,6,7,8,9首先,我们将数据按照升序排列得到1,2,3,4,5,6,7,8,9、选择中间的元素5作为根节点。

然后,我们将数据分成两部分:1,2,3,4和6,7,8,9、递归地对这两个部分进行构造。

对于左子树,我们选择中间元素2作为根节点,将数据分成两部分:1和3,4、递归地构造这两个部分。

对于右子树,我们选择中间元素8作为根节点,将数据分成两部分:6,7和9、递归地构造这两个部分。

重复这个过程,直到所有的数据都被构造为节点。

最后得到的树就是一个平衡二叉树。

这个构造方法的时间复杂度是O(nlogn),其中n是数据的数量。

虽然它的时间复杂度比较高,但是它保证了构造的树是一个平衡二叉树,从而提高了数据的查找、插入和删除等操作的效率。

总结起来,通过AVL树进行构造是一种有效的方法来构造平衡二叉树。

它将数据按照升序或者降序排列,选择中间元素作为根节点,然后递归地对左子树和右子树进行构造。

这种方法保证了构造的树是一个平衡二叉树,从而提高了数据的查找、插入和删除等操作的效率。

平衡二叉树的手动调整方法

平衡二叉树的手动调整方法

平衡⼆叉树的⼿动调整⽅法看书左旋右旋看着懵逼,不懂往左旋转往右旋转到底是怎么个旋转法。

总结了⼀个万能的⼿动调整⽅法,不⽤记忆什么LL,LR,RL,RR的形式,通吃。

当新插⼊⼀个节点,导致不平衡,进⾏⼿动调整。

步骤有四步:1。

找到最⼩不平衡⼦树(和其根节点)2。

从根节点出发,沿插⼊路径找三个节点。

3。

调整这三个节点。

(找出中位数,让中位数作为根节点,其余两个⼀左⼀右)4。

剩下的节点,左右⼦树的位置保持不变,再找到最后⼀个节点的插⼊位置。

(1)先以三个节点的情况演⽰,假设插⼊了15,3,7,出现不平衡。

最⼩不平衡⼦树就是三个节点。

找出中位数7,作为根节点。

然后3放到左边,15放到右边。

调整完成。

(2)继续插⼊10和9,导致不平衡。

最⼩不平衡⼦树如图所⽰。

从根节点出发找到三个节点。

调整这三个节点的位置,⽅法和上⾯⼀样,把中位数10作为根节点。

(3)继续插⼊8导致不平衡,以及最⼩不平衡⼦树。

7是根节点。

从7开始,找到7,10,9三个节点。

调整这三个。

让9做根节点,7在左,10在右。

对于剩下的节点,左右⼦树位置保持不变。

3仍然在最左,15仍然在最右。

然后再找到8应该插在哪⾥就⾏了。

调整完成。

复述⼀遍⽅法:1。

找到最⼩不平衡⼦树(和其根节点)2。

从根节点出发,沿插⼊路径找三个节点。

3。

调整这三个节点。

(找出中位数,让中位数作为根节点,其余两个⼀左⼀右)4。

剩下的节点,左右⼦树的位置保持不变,再找到最后⼀个节点的插⼊位置。

这套⽅法万能,不⽤记书上的四种样式。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

平衡二叉树操作的演示1.需求分析本程序是利用平衡二叉树,实现动态查找表的基本功能:创建表,查找、插入、删除。

具体功能:(1)初始,平衡二叉树为空树,操作界面给出创建、查找、插入、删除、合并、分裂六种操作供选择。

每种操作均提示输入关键字。

每次插入或删除一个结点后,更新平衡二叉树的显示。

(2)平衡二叉树的显示采用凹入表现形式。

(3)合并两棵平衡二叉树。

(4)把一棵二叉树分裂为两棵平衡二叉树,使得在一棵树中的所有关键字都小于或等于x,另一棵树中的任一关键字都大于x。

如下图:2.概要设计平衡二叉树是在构造二叉排序树的过程中,每当插入一个新结点时,首先检查是否因插入新结点而破坏了二叉排序树的平衡性,若是则找出其中的最小不平衡子树,在保持二叉排序树特性的前提下,调整最小不平衡子树中各结点之间的链接关系,进行相应的旋转,使之成为新的平衡子树。

具体步骤:(1)每当插入一个新结点,从该结点开始向上计算各结点的平衡因子,即计算该结点的祖先结点的平衡因子,若该结点的祖先结点的平衡因子的绝对值不超过1,则平衡二叉树没有失去平衡,继续插入结点;(2)若插入结点的某祖先结点的平衡因子的绝对值大于1,则找出其中最小不平衡子树的根结点;(3)判断新插入的结点与最小不平衡子树的根结点个关系,确定是那种类型的调整;(4)如果是LL型或RR型,只需应用扁担原理旋转一次,在旋转过程中,如果出现冲突,应用旋转优先原则调整冲突;如果是LR型或RL型,则需应用扁担原理旋转两次,第一次最小不平衡子树的根结点先不动,调整插入结点所在子树,第二次再调整最小不平衡子树,在旋转过程中,如果出现冲突,应用旋转优先原则调整冲突;(5)计算调整后的平衡二叉树中各结点的平衡因子,检验是否因为旋转而破坏其他结点的平衡因子,以及调整后平衡二叉树中是否存在平衡因子大于1的结点。

流程图3.详细设计二叉树类型定义:typedef int Status;typedef int ElemType;typedef struct BSTNode{ElemType data;int bf;struct BSTNode *lchild ,*rchild;} BSTNode,* BSTree;Status SearchBST(BSTree T,ElemType e)//查找void R_Rotate(BSTree &p)//右旋void L_Rotate(BSTree &p)//左旋void LeftBalance(BSTree &T)//插入平衡调整void RightBalance(BSTree &T)//插入平衡调整Status InsertAVL(BSTree &T,ElemType e,int &taller)//插入void DELeftBalance(BSTree &T)//删除平衡调整void DERightBalance(BSTree &T)//删除平衡调整Status Delete(BSTree &T,int &shorter)//删除操作Status DeleteAVL(BSTree &T,ElemType e,int &shorter)//删除操作void merge(BSTree &T1,BSTree &T2)//合并操作void splitBSTree(BSTree T,ElemType e,BSTree &T1,BSTree &T2)//分裂操作void PrintBSTree(BSTree &T,int lev)//凹入表显示附录源代码:#include<stdio.h>#include<stdlib.h>//#define TRUE 1//#define FALSE 0//#define OK 1//#define ERROR 0#define LH +1#define EH 0#define RH -1//二叉类型树的类型定义typedef int Status;typedef int ElemType;typedef struct BSTNode{ElemType data;int bf;//结点的平衡因子struct BSTNode *lchild ,*rchild;//左、右孩子指针} BSTNode,* BSTree;/*查找算法*/Status SearchBST(BSTree T,ElemType e){if(!T){return 0; //查找失败}else if(e == T->data ){return 1; //查找成功}else if (e < T->data){return SearchBST(T->lchild,e);}else{return SearchBST(T->rchild,e);}}//右旋void R_Rotate(BSTree &p){BSTree lc; //处理之前的左子树根结点lc = p->lchild; //lc指向的*p的左子树根结点p->lchild = lc->rchild; //lc的右子树挂接为*P的左子树lc->rchild = p;p = lc; //p指向新的根结点}//左旋void L_Rotate(BSTree &p){BSTree rc;rc = p->rchild; //rc指向的*p的右子树根结点p->rchild = rc->lchild; //rc的左子树挂接为*p的右子树rc->lchild = p;p = rc; //p指向新的根结点}//对以指针T所指结点为根结点的二叉树作左平衡旋转处理,//本算法结束时指针T指向新的根结点void LeftBalance(BSTree &T){BSTree lc,rd;lc=T->lchild;//lc指向*T的左子树根结点switch(lc->bf){ //检查*T的左子树的平衡度,并做相应的平衡处理case LH: //新结点插入在*T的左孩子的左子树,要做单右旋处理T->bf = lc->bf=EH;R_Rotate(T);break;case RH: //新结点插入在*T的左孩子的右子树上,做双旋处理rd=lc->rchild; //rd指向*T的左孩子的右子树根switch(rd->bf){ //修改*T及其左孩子的平衡因子case LH: T->bf=RH; lc->bf=EH;break;case EH: T->bf=lc->bf=EH;break;case RH: T->bf=EH; lc->bf=LH;break;}rd->bf=EH;L_Rotate(T->lchild); //对*T的左子树作左旋平衡处理R_Rotate(T); //对*T作右旋平衡处理}}//右平衡旋转处理void RightBalance(BSTree &T){BSTree rc,ld;rc=T->rchild;switch(rc->bf){case RH:T->bf= rc->bf=EH;L_Rotate(T);break;case LH:ld=rc->lchild;switch(ld->bf){case LH: T->bf=RH; rc->bf=EH;break;case EH: T->bf=rc->bf=EH;break;case RH: T->bf = EH; rc->bf=LH;break;}ld->bf=EH;R_Rotate(T->rchild);L_Rotate(T);}}//插入结点Status InsertAVL(BSTree &T,ElemType e,int &taller){//taller反应T长高与否if(!T){//插入新结点,树长高,置taller为trueT= (BSTree) malloc (sizeof(BSTNode));T->data = e;T->lchild = T->rchild = NULL;T->bf = EH;taller = 1;}else{if(e == T->data){taller = 0;return 0;}if(e < T->data){if(!InsertAVL(T->lchild,e,taller))//未插入return 0;if(taller)//已插入到*T的左子树中且左子树长高switch(T->bf){//检查*T的平衡度,作相应的平衡处理case LH:LeftBalance(T);taller = 0;break;case EH:T->bf = LH;taller = 1;break;case RH:T->bf = EH;taller = 0;break;}}else{if (!InsertAVL(T->rchild,e,taller)){return 0;}if(taller)//插入到*T的右子树且右子树增高switch(T->bf){//检查*T的平衡度case LH:T->bf = EH;taller = 0;break;case EH:T->bf = RH;taller = 1;break;case RH:RightBalance(T);taller = 0;break;}}}return 1;}void DELeftBalance(BSTree &T){//删除平衡调整BSTree lc,rd;lc=T->lchild;switch(lc->bf){case LH:T->bf = EH;//lc->bf= EH;R_Rotate(T);break;case EH:T->bf = EH;lc->bf= EH;R_Rotate(T);break;case RH:rd=lc->rchild;switch(rd->bf){case LH: T->bf=RH; lc->bf=EH;break;case EH: T->bf=lc->bf=EH;break;case RH: T->bf=EH; lc->bf=LH;break;}rd->bf=EH;L_Rotate(T->lchild);R_Rotate(T);}}void DERightBalance(BSTree &T) //删除平衡调整{BSTree rc,ld;rc=T->rchild;switch(rc->bf){case RH:T->bf= EH;//rc->bf= EH;L_Rotate(T);break;case EH:T->bf= EH;//rc->bf= EH;L_Rotate(T);break;case LH:ld=rc->lchild;switch(ld->bf){case LH: T->bf=RH; rc->bf=EH;break;case EH: T->bf=rc->bf=EH;break;case RH: T->bf = EH; rc->bf=LH;break;}ld->bf=EH;R_Rotate(T->rchild);L_Rotate(T);}}void SDelete(BSTree &T,BSTree &q,BSTree &s,int &shorter){if(s->rchild){SDelete(T,s,s->rchild,shorter);if(shorter)switch(s->bf){case EH:s->bf = LH;shorter = 0;break;case RH:s->bf = EH;shorter = 1;break;case LH:DELeftBalance(s);shorter = 0;break;}return;}T->data = s->data;if(q != T)q->rchild = s->lchild;elseq->lchild = s->lchild;shorter = 1;}//删除结点Status Delete(BSTree &T,int &shorter){ BSTree q;if(!T->rchild){q = T;T = T->lchild;free(q);shorter = 1;}else if(!T->lchild){q = T;T= T->rchild;free(q);shorter = 1;}else{SDelete(T,T,T->lchild,shorter);if(shorter)switch(T->bf){case EH:T->bf = RH;shorter = 0;break;case LH:T->bf = EH;shorter = 1;break;case RH:DERightBalance(T);shorter = 0;break;}}return 1;}Status DeleteAVL(BSTree &T,ElemType e,int &shorter){ int sign = 0;if (!T){return sign;}else{if(e == T->data){sign = Delete(T,shorter);return sign;}else if(e < T->data){sign = DeleteAVL(T->lchild,e,shorter);if(shorter)switch(T->bf){case EH:T->bf = RH;shorter = 0;break;case LH:T->bf = EH;shorter = 1;break;case RH:DERightBalance(T);shorter = 0;break;}return sign;}else{sign = DeleteAVL(T->rchild,e,shorter);if(shorter)switch(T->bf){case EH:T->bf = LH;shorter = 0;break;case RH:T->bf = EH;break;case LH:DELeftBalance(T);shorter = 0;break;}return sign;}}}//合并void merge(BSTree &T1,BSTree &T2){int taller = 0;if(!T2)return;merge(T1,T2->lchild);InsertAVL(T1,T2->data,taller);merge(T1,T2->rchild);}//分裂void split(BSTree T,ElemType e,BSTree &T1,BSTree &T2){ int taller = 0;if(!T)return;split(T->lchild,e,T1,T2);if(T->data > e)InsertAVL(T2,T->data,taller);elseInsertAVL(T1,T->data,taller);split(T->rchild,e,T1,T2);}//分裂void splitBSTree(BSTree T,ElemType e,BSTree &T1,BSTree &T2){ BSTree t1 = NULL,t2 = NULL;split(T,e,t1,t2);T1 = t1;T2 = t2;return;}//构建void CreatBSTree(BSTree &T){int num,i,e,taller = 0;printf("输入结点个数:");scanf("%d",&num);printf("请顺序输入结点值\n");for(i = 0 ;i < num;i++){printf("第%d个结点的值",i+1);scanf("%d",&e);InsertAVL(T,e,taller) ;}printf("构建成功,输入任意字符返回\n");getchar();getchar();}//凹入表形式显示方法void PrintBSTree(BSTree &T,int lev){int i;if(T->rchild)PrintBSTree(T->rchild,lev+1);for(i = 0;i < lev;i++)printf(" ");printf("%d\n",T->data);if(T->lchild)PrintBSTree(T->lchild,lev+1);void Start(BSTree &T1,BSTree &T2){int cho,taller,e,k;taller = 0;k = 0;while(1){system("cls");printf(" 平衡二叉树操作的演示 \n\n");printf("********************************\n");printf(" 平衡二叉树显示区 \n");printf("T1树\n");if(!T1 )printf("\n 当前为空树\n");else{PrintBSTree(T1,1);}printf("T2树\n");if(!T2 )printf("\n 当前为空树\n");elsePrintBSTree(T2,1);printf("\n********************************************************************* *********\n");printf("T1操作:1.创建 2.插入 3.查找 4.删除 10.分裂\n");printf("T2操作:5.创建 6.插入 7.查找 8.删除 11.分裂\n");printf(" 9.合并 T1,T2 0.退出\n");printf("*********************************************************************** *******\n");printf("输入你要进行的操作:");scanf("%d",&cho);switch(cho){case 1:CreatBSTree(T1);break;case 2:printf("请输入要插入关键字的值");scanf("%d",&e);InsertAVL(T1,e,taller) ;break;case 3:printf("请输入要查找关键字的值");scanf("%d",&e);if(SearchBST(T1,e))printf("查找成功!\n");elseprintf("查找失败!\n");printf("按任意键返回87"); getchar();getchar();break;case 4:printf("请输入要删除关键字的值"); scanf("%d",&e);if(DeleteAVL(T1,e,k))printf("删除成功!\n");elseprintf("删除失败!\n");printf("按任意键返回");getchar();getchar();break;case 5:CreatBSTree(T2);break;case 6:printf("请输入要插入关键字的值"); scanf("%d",&e);InsertAVL(T2,e,taller) ;break;case 7:printf("请输入要查找关键字的值"); scanf("%d",&e);if(SearchBST(T2,e))printf("查找成功!\n");elseprintf("查找失败!\n");printf("按任意键返回");getchar();getchar();break;case 8:printf("请输入要删除关键字的值"); scanf("%d",&e);if(DeleteAVL(T2,e,k))printf("删除成功!\n");elseprintf("删除失败!\n");printf("按任意键返回");getchar();getchar();break;case 9:merge(T1,T2);T2 = NULL;printf("合并成功,按任意键返回"); getchar();getchar();break;case 10:printf("请输入要中间值字的值"); scanf("%d",&e);splitBSTree(T1,e,T1,T2) ;printf("分裂成功,按任意键返回"); getchar();getchar();break;case 11:printf("请输入要中间值字的值"); scanf("%d",&e);splitBSTree(T2,e,T1,T2) ;printf("分裂成功,按任意键返回"); getchar();getchar();break;case 0:system("cls");exit(0);}}}main(){BSTree T1 = NULL;BSTree T2 = NULL;Start(T1,T2);}。

相关文档
最新文档