巧绘平衡二叉排序树

合集下载

二叉树再平衡的方法

二叉树再平衡的方法

二叉树再平衡的方法二叉树再平衡是指在二叉树失衡的情况下,调整二叉树的结构,使其恢复平衡的过程。

二叉树的失衡是指左子树或右子树的深度与另一侧的深度差大于1。

失衡的二叉树会影响查找、插入、删除等操作的效率,因此需要进行再平衡处理。

二叉树再平衡一般有两种方法:旋转和重构。

旋转是指通过对节点之间的旋转来达到平衡的目的。

旋转分为左旋和右旋两种。

左旋:将节点的右子节点变为该节点的父节点,该节点成为其右子节点的左子节点,并将其右子节点的左子节点变为该节点的右子节点。

右旋:将节点的左子节点变为该节点的父节点,该节点成为其左子节点的右子节点,并将其左子节点的右子节点变为该节点的左子节点。

重构是指通过重新构建一棵新的平衡二叉树来达到平衡的目的。

重构有两种方法:AVL树和红黑树。

AVL树是一种严格平衡的二叉树,它的每个节点的左子树和右子树的高度差不超过1。

插入或删除节点时,如果会导致AVL树失衡,则需要通过旋转操作使其恢复平衡。

AVL树的查询、插入和删除操作的时间复杂度都是O(logn),但是需要频繁地进行旋转操作,导致空间复杂度较高。

红黑树是一种近似平衡的二叉树,它的每个节点要么是红色要么是黑色,并且满足以下性质:1. 根节点是黑色的。

2. 每个叶子节点是黑色的空节点(NIL节点)。

3. 每个红色节点的两个子节点都是黑色的。

4. 从任意一个节点到其子树中每个叶子节点的路径上都包含相同数目的黑色节点。

通过这些性质,红黑树保证了其近似平衡的特点。

插入或删除节点时,通过变换节点颜色和旋转操作来保证红黑树的平衡。

红黑树的查询、插入和删除操作的时间复杂度都是O(logn),且旋转操作较少,空间复杂度较低,因此应用广泛。

综上所述,二叉树再平衡可以通过旋转和重构两种方法来实现。

不同的方法适用于不同的场景和需求,我们需要根据具体情况选择合适的再平衡方法,以提高二叉树的效率和稳定性。

构造平衡二叉排序树

构造平衡二叉排序树

构造平衡二叉排序树程序如下:#include"stdio.h"#include"stdlib.h"typedef int KeyType;typedef struct node{KeyType key;struct node *lchild,*rchild;}BSTNode;typedef BSTNode *BSTree;BSTree CreateBST(void);void DelBSTNode(BSTree *Tptr,KeyType Key);void InorderBST(BSTree T);void InsertBST(BSTree *bst,KeyType key);main(){BSTree T;char ch1,ch2;KeyType Key;printf("建立一棵二叉排序树的二叉链表存储\n");T=CreateBST();ch1='y';while (ch1=='y'||ch1=='Y'){printf("请选择下列操作:\n");printf("1------更新二叉树上的存储\n");printf("2------二叉排序树上的删除\n");printf("3------二叉排序树中序输出\n");printf("4------退出\n");scanf("\n%c",&ch2);switch(ch2){case '1':T=CreateBST();break;case '2':printf("\n请输入要删除的数据:");scanf("\n%d",&Key);DelBSTNode(&T,Key);printf("删除操作完毕.\n");break;case '3':InorderBST(T);printf("\n二叉排序树输出完毕.\n");break;case '4':ch1='n';break;default:ch1='n';}}}void InsertBST(BSTree *bst,KeyType key){BSTree s;if(*bst==NULL) /*递归结束条件*/{s=(BSTree)malloc(sizeof(BSTNode)); /*申请新的结点*/ s->key=key;s->lchild=NULL;s->rchild=NULL;*bst=s;}elseif(key<(*bst)->key)InsertBST(&((*bst)->lchild),key); /*将S插入左子树*/ elseif(key>(*bst)->key)InsertBST(&((*bst)->rchild),key); /*将S插入右子树*/ }BSTree CreateBST(void){BSTree T;KeyType Key;T=NULL;printf("请输入一个关键字(输入0时结束输入):\n"); scanf("%d",&Key);while(Key){InsertBST(&T,Key);printf("请输入下一个关键字(输入0时结束输入):\n"); scanf("\n%d",&Key);}return T;}void DelBSTNode(BSTree *T,KeyType Key) {BSTNode *parent=NULL,*p,*q,*child;p=*T;while(p){if(p->key==Key) break;parent=p;p=(Key<p->key)?p->lchild:p->rchild;}if(!p){printf("没有找到要删除的结点\n");return;}q=p;if(q->lchild && q->rchild)for(parent=q,p=q->rchild;p->lchild;parent=q,p=p->lchild); child=(p->lchild)?p->lchild:p->rchild;if(!parent)*T=child;else{if(p==parent->lchild)parent->lchild=child;elseparent->rchild=child;if(p!=q)q->key=p->key;}free(p);}void InorderBST(BSTree T){if(T!=NULL){InorderBST(T->lchild);printf("%5d",T->key);InorderBST(T->rchild);}}实验结果:建立二叉检索树并输入数据:输出数据:(二叉检索树中序输出)删除二叉检索树中的一个点:最后的输出结果:(二叉检索树中序输出)。

二叉平衡排序树

二叉平衡排序树

《数据结构》课程设计报告专业:班级:姓名:指导教师:学号:2010年 7 月 5 日二叉平衡排序树一、课程设计内容问题描述:从一棵空树开始创建,在创建过程中,保证树的有序性,同时还要针对树的平衡性做些调整。

最终要把创建好的二叉排序树转换为二叉平衡排序树。

基本要求:1.创建(插入、调整、改组)2.输出二、主要算法说明1、.主要数据结构定义typedef struct node node;struct node{node* parent;node* left;node* right;int balance; //左右子树高度之差int key;};2、主要函数说明int searchNode(int key, node* root, node** parent) :按key查找结点node* minNode(node* root) :树root的最小结点node* maxNode(node* root) :树root的最大结点node* preNode(node* target) :求前驱结点node* nextNode(node* target) :求后继结点node* adjustAVL(node* root, node* parent, node* child) :调整,保证二叉树的平衡性node* insertNode(int key, node* root) :插入node* deleteNode(int key, node* root) :删除node* createAVL(int *data, int size) :建造新的二叉树void interordertraverse(node* root) :中序遍历void preordertraverse(node* root) :先序遍历3、二叉排序树的插入和删除a. 二叉排序树的插入在二叉排序树中插入新结点,要保证插入后的二叉树仍符合二叉排序树的定义。

排序二叉树和平衡二叉树

排序二叉树和平衡二叉树

9.2.1 二叉排序树和平衡二叉树一、二叉排序树及其查找过程什么是二叉排序树?二叉排序树(Binary Sort Tree)或者是一棵空树;或者是具有下列性质的二叉树:(1)若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;(2)若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;(3)它的左、右子树也分别为二叉排序树。

二叉排序树又称二叉查找树,根据上述定义的结构特点可见,它的查找过程和次优二叉树类似。

即当二叉排序树不空时,首先将给定值和根结点的关键字比较,若相等,则查找成功,否则将依据给定值和根结点的关键字之间的大小关系,分别在左子树或右子树上继续进行查找。

通常,可取二叉链表作为二叉排序树的存储结构,则上述查找过程如算法 9.5(a)所描述。

BiTree SearchBST (BiTree T,KeyType key){ //在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针if( (!T)||EQ(key,T—>data.key))return (T); //查找结束else if LT(key,T—>data.key)return(SearchBST(T—>lchild,key)); //在左子树中继续查找elsereturn(SearchBST(T —>rchild,key));// 在右子树中继续查找}//SearchBST算法 9.5(a)图9.7 二叉排序树示例[例如]:在图9.7所示的二叉排序树中查找关键字等于100的记录(树中结点内的数均为记录的关键字)。

首先以 key=100和根结点的关键字比较,因为key>45,则查找以45为根的右子树,此时右子树不空,且key>53,则继续查找以53为根的右子树,由于key和53的右子树根的关键字100相等,则查找成功,返回指向结点100的指针值。

算法(平衡二叉树)

算法(平衡二叉树)

算法(平衡⼆叉树)科普⼆叉树⼆叉树⼆叉数是每个节点最多有两个⼦树,或者是空树(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);}};...................................................................................................................############################################################################ ###################################################################################。

数据结构53:二叉排序树(二叉查找树)

数据结构53:二叉排序树(二叉查找树)

数据结构53:⼆叉排序树(⼆叉查找树)前⼏节介绍的都是有关静态查找表的相关知识,从本节开始介绍另外⼀种查找表——动态查找表。

动态查找表中做查找操作时,若查找成功可以对其进⾏删除;如果查找失败,即表中⽆该关键字,可以将该关键字插⼊到表中。

动态查找表的表⽰⽅式有多种,本节介绍⼀种使⽤树结构表⽰动态查找表的实现⽅法——⼆叉排序树(⼜称为“⼆叉查找树”)。

什么是⼆叉排序树?⼆叉排序树要么是空⼆叉树,要么具有如下特点:⼆叉排序树中,如果其根结点有左⼦树,那么左⼦树上所有结点的值都⼩于根结点的值;⼆叉排序树中,如果其根结点有右⼦树,那么右⼦树上所有结点的值都⼤⼩根结点的值;⼆叉排序树的左右⼦树也要求都是⼆叉排序树;例如,图 1 就是⼀个⼆叉排序树:图 1 ⼆叉排序树使⽤⼆叉排序树查找关键字⼆叉排序树中查找某关键字时,查找过程类似于次优⼆叉树,在⼆叉排序树不为空树的前提下,⾸先将被查找值同树的根结点进⾏⽐较,会有 3 种不同的结果:如果相等,查找成功;如果⽐较结果为根结点的关键字值较⼤,则说明该关键字可能存在其左⼦树中;如果⽐较结果为根结点的关键字值较⼩,则说明该关键字可能存在其右⼦树中;实现函数为:(运⽤递归的⽅法)BiTree SearchBST(BiTree T, KeyType key){// 如果递归过程中 T 为空,则查找结果,返回NULL;或者查找成功,返回指向该关键字的指针if (!T || key==T->data) {return T;} else if(key<T->data) {// 递归遍历其左孩⼦return SearchBST(T->lchild, key);} else {// 递归遍历其右孩⼦return SearchBST(T->rchild, key);}}⼆叉排序树中插⼊关键字⼆叉排序树本⾝是动态查找表的⼀种表⽰形式,有时会在查找过程中插⼊或者删除表中元素,当因为查找失败⽽需要插⼊数据元素时,该数据元素的插⼊位置⼀定位于⼆叉排序树的叶⼦结点,并且⼀定是查找失败时访问的最后⼀个结点的左孩⼦或者右孩⼦。

平衡二叉树(AVL树)的基本操作(附有示意图)

平衡二叉树(AVL树)的基本操作(附有示意图)

平衡二叉树关于树的深度是平衡的,具有较高的检索效率。

平衡二叉树或是一棵空树,或是具有下列性质的二叉排序树:其左子树和右子树都是平衡二叉树,而且左右子树深度之差绝对值不超过1. 由此引出了平衡因子(balance factor)的概念,bf定义为该结点的左子树的深度减去右子树的深度(有些书是右子树深度减去左子树深度,我是按照左子树减去右子树来计算的,下面的代码也是这样定义的),所以平衡二叉树的结点的平衡因子只可能是-1,0,1 ,某个结点的平衡因子绝对值大于1,该二叉树就不平衡。

平衡二叉树在出现不平衡状态的时候,要进行平衡旋转处理,有四种平衡旋转处理(单向右旋处理,单向左旋处理,双向旋转(先左后右)处理,双向旋转(先右后左)处理),归根到底是两种(单向左旋处理和单向右旋处理)。

文件"tree.h"view plain1.#include<iostream>2.#include<stack>3.#include<queue>ing namespace std;5.6.const int LH=1; //左子树比右子树高17.const int EH=0; //左右子树一样高8.const int RH=-1;//右子树比左子树高19.const int MAX_NODE_NUM=20; //结点数目上限10.11.class AVL_Tree;12.13.class AvlNode14.{15.int data;16.int bf; //平衡因子17. AvlNode *lchild;18. AvlNode *rchild;19.friend class AVL_Tree;20.};21.22.class AVL_Tree23.{24.public:25.int Get_data(AvlNode *p)26. {27.return p->data;28. }29.30.void Create_AVl(AvlNode *&T) //建树31. {32. cout<<"输入平衡二叉树的元素,输入-1代表结束输入:";33.int num[MAX_NODE_NUM];34.int a,i=0;35.while(cin>>a && a!=-1)36. {37. num[i]=a;38. i++;39. }40.41.if(num[0]==-1)42. {43. cout<<"平衡树为空"<<endl;44. T=NULL;45.return;46. }47.48.int k=i;49.bool taller=false;50.for(i=0;i<k;i++)51. Insert_Avl(T,num[i],taller);//逐个进行插入,插入过程看下面的示意图52. cout<<"_____建树完成____"<<endl;53. }54.55.void L_Rotate(AvlNode *&p)56. {57.//以p为根节点的二叉排序树进行单向左旋处理58. AvlNode *rc=p->rchild;59. p->rchild=rc->lchild;60. rc->lchild=p;61. p=rc;62. }63.64.void R_Rotate(AvlNode *&p)65. {66.//以p为根节点的二叉排序树进行单向右旋处理67. AvlNode *lc=p->lchild;68. p->lchild=lc->rchild;69. lc->rchild=p;70. p=lc;71. }72.73.void Left_Balance(AvlNode *&T)74. {75.//以T为根节点的二叉排序树进行左平衡旋转处理76. AvlNode *lc,*rd;77. lc=T->lchild;78.switch(lc->bf)79. {80.case LH:81.//新结点插在T的左孩子的左子树上,做单向右旋处理82. T->bf=lc->bf=EH;83. R_Rotate(T);84.break;85.case RH:86.//新结点插在T的左孩子的右子树上,要进行双旋平衡处理(先左后右)87. rd=lc->rchild;88.switch(rd->bf)89. {90.case LH:91.//插在右子树的左孩子上92. T->bf=RH;93. lc->bf=EH;94.break;95.case EH:96. T->bf=lc->bf=EH;97.break;98.case RH:99. T->bf=EH;100. lc->bf=LH;101.break;102. }103. rd->bf=EH;104. L_Rotate(T->lchild);//先对T的左子树进行单向左旋处理105. R_Rotate(T); //再对T进行单向右旋处理106. }107. }108.109.void Right_Balance(AvlNode *&T)110. {111.//以T为根节点的二叉排序树进行右平衡旋转处理112. AvlNode *rc,*ld;113. rc=T->rchild;114.switch(rc->bf)115. {116.case RH:117.//新结点插在右孩子的右子树上,进行单向左旋处理118. T->bf=rc->bf=EH;119. L_Rotate(T);120.break;121.case LH:122.//新结点插在T的右孩子的左子树上,要进行右平衡旋转处理(先右再左)123. ld=rc->lchild;124.switch(ld->bf)125. {126.case LH:127. T->bf=LH;128. rc->bf=EH;129.break;130.case EH:131. T->bf=rc->bf=EH;132.break;133.case RH:134. T->bf=EH;135. rc->bf=RH;136.break;137. }138. ld->bf=EH;139. R_Rotate(T->rchild);//先对T的右子树进行单向右旋处理140. L_Rotate(T); //再对T进行单向左旋处理141. }142. }143.144.bool Insert_Avl(AvlNode *&T,int num,bool &taller) //插入145. {146.//若在平衡二叉树中不存在结点值和num一样大小的结点147.//则插入值为num的新结点,并返回true148.//若因为插入而使得二叉排序树失去平衡,则做平衡旋转处理149.//taller反映树是否长高150.151.if(!T)152. {153.//插入新结点,树长高,taller为true154. T=new AvlNode;155. T->data=num;156. T->lchild=T->rchild=NULL;157. T->bf=EH;158. taller=true;159. }161. {162.if(num==T->data)163. {164.//不重复插入165. taller=false;166.return false;167. }168.if(num<T->data) //继续在T的左子树中进行搜索169. {170.if(!Insert_Avl(T->lchild,num,taller))//插入不成功171.return false;172.if(taller) //已插入T的左子树,且左子树长高173. {174.switch(T->bf)175. {176.case LH:177./*—————————————————————178. / 插入前左子树高于右子树,需要进行做平衡处理179. / 不管是单向左旋处理,还是先左后右平衡处理180. / 处理结果都是使得插入新结点后,树的高度不变181. /—————————————————————*/182.183. Left_Balance(T);184. taller=false;185.break;186.case EH:187.//插入前左右子树等高,现在插入新街点后,左子树比右子树高188.189. T->bf=LH;190. taller=true;191.break;192.case RH:193.//插入前右子树比左子树高,现在新结点插入左子树后,树变为左右子树等高194.195. T->bf=EH;196. taller=false;197.break;198.199. }200. }201. }202.else204.//num>T->data 在T的右子树中继续搜索205.if(!Insert_Avl(T->rchild,num,taller))206.return false;207.if(taller)208. {209.switch(T->bf)210. {211.case LH:212.//插入前左子树比右子树高,现在插入T的右子树后,左右子树等高213.214. T->bf=EH;215. taller=false;216.break;217.case EH:218.//插入前左右子树等高,现在插入后,右子树比左子树高219.220. T->bf=RH;221. taller=true;222.break;223.224.case RH:225.//插入前右子树比坐子树高,插入后,排序树失去平衡,需要进行右平衡处理226. Right_Balance(T);227. taller=false;228.break;229.230. }231. }232. }233. }234.return true;235. }236.237.bool Search_Avl(AvlNode *T,int num,AvlNode *&f,AvlNode *&p) //搜索238. {239.//用p带回查找到的顶点的地址,f带回p的双亲结点240. p=T;241.while(p)242. {243.if(p->data==num)244.return true;245.if(p->data>num)246. {247. f=p;248. p=p->lchild;249. }250.else251. {252. f=p;253. p=p->rchild;254. }255. }256.return false;257. }258.259.void Delete_AVL(AvlNode *&T,int num) //删除260. {261./*---------------------------------------------------------262. / 从树中删除一个节点后,要保证删后的树还是一棵平衡二叉树,263. / 删除前,首先是在树中查找是否有这个结点,用p指向该结点,264. / 用f指向p的双亲结点,这个结点在树中的位置有下面四种情况: 265. / 266. / 1:如果p指向的结点是叶子结点,那么直接将f指针的左子树或者267. / 右子树置空,然后删除p结点即可。

二叉平衡树精编版

二叉平衡树精编版

0
50
2)新结点插在平衡因子值为1的结点的右分支,或者 -1的结点的左分支,该结点也不会造成不平衡。
左重结点
右重结点
10
-01
50
50
40 55
35 60
平衡二叉树的构造
3)新结点插在平衡因子值为1的结点的左分支上,或 者为-1的结点的右分支上,此时,该结点的平衡因子的 绝对值大于1,造成二叉排序树不平衡。
所以,含有n个结点的二叉排序树的平均查找长度和 树的形态有关。 在某些情况下,需要将二叉排序树进行平衡化处理, 将其调整为平衡二叉树时,来提高它的查找性能。
平衡二叉树
二叉平衡树:又称AVL树是二叉排序树的另一 种形式,其特点为:
树中每个结点的左、右子树深度之差的绝对值 不大于1,即 hL-hR <=1 。
BR h
X
平衡二叉树的构造
4.RL型 新结点插在右重结点a( a是离新结点插入位置最近的右重
结点地址)的右孩子的左孩子的右分支上。如下图棕色代
表新结点,称RL型。
-2
-1 A
A
h-1 AL
0
B
C
h-1 AL
1
B
-1
C
BR h-1
BR h-1
h-2 CL h-2 CR
h-2 CL
CR
h-1
X
平衡二叉树的构造
平衡二叉树
结点的平衡因子:该结点的左子树的深度减去 它的右子树的深度 平衡二叉树所有结点的平衡因子只可能为: -1,0,1。
平衡二叉树
2
5
2
0
4
8
1
2
0
1
平衡因子 >1
1
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1 平衡二叉排序树( 又称 AV 树)
1.1 一棵非空的平衡二叉排序树具有如下性质 ( 1) 左子树与右子树的高度之差的绝对值小于 1; ( 2) 左子树和右子树也是平衡二叉排序树。
1.2 平衡因子
平衡因子是指结点的左子树深度和右子树深度 之差。对于一棵平衡二叉平衡排序树而言, 其所有结 点的平衡因子只能是- 1, 0, 1。
如图 5 所示是一棵平衡二叉排序树, 当插入一个 机 新结点 15 后, 失去平衡, 如图 6, 经 过 前 面 的 调 整 方 (总
图 1 所示; ②在左子树的右子树上插入一个新结点
法得到一棵平衡二叉排序树如图 7 所示。



收稿日期: 2007- 07- 10 修稿日期: 2007- 08- 17
关键词: 平衡因子; 平衡二叉排序树; 数据结构
0 引言
N, 即 LR 型( Left,Right) ,如图 2 所示。
《数据结构》课程是计算机专业的核心课程, 在信 息 科 学 中 具 有 重 要 的 地 位 。学 好 《数 据 结 构 》是 提 高 软 件设计水平的关键性步骤。同时, 《数据结构》是硕士 研究生考试计算机类专业的必考科目, 也是相关专业 的 考 试 科 目 。考 试 大 纲 中 明 确 指 出 要 熟 练 掌 握 手 工 绘 制平衡二叉排序树。
图 12
图 13
图14
详细调整步骤如下: 第一步: 以平衡因子为- 1 的结点 40 作为根结点 ( 这里有两个平衡因子为- 1 的结点, 可选择靠近根结 点的那个; 第二步: 平衡因子为- 1 的结点 40 的左右子树采 用相邻赋予, 即: 把结点 30 给予结点 20, 作为其右子 树; 第三步: 以平衡因子为- 2 的结点及其子树作为 根结点的左子树, 根结点的右子树则由原平衡因子 为- 1 的结点的右子树代替。
则: 图 8 和图 9 调整后恢复平衡的图如图 10 和
图 11。
图5
图6
图7
详细调整步骤如下: ①把平衡因子为 1 的结点 25 作为根结点 ( 这里 结点 20 的平衡因子也是 1, 依然采取就近原则, 取 25 作为根结点) ; ②平衡因子为 1 结点 25 其原有的左右子树采用 相邻赋予, 即: 把结点 30 给予结点 40, 作为它的左子 树; ③取平衡因子为 2 的结点 40 其原有的右子树作 为根结点的右子树; 结点 25 的左边没有结点, 则把其 左子树作为根结点的左子树。
实践与经验
巧绘平衡二叉排序树
潘兆庆 1 , 周彩根 2
( 1. 盐城师范学院黄海学院信息科与技术学院, 盐城 224002; 2.盐城师范学院信息科学与技术学院, 盐城 224002)
摘 要: 一棵失衡的二叉树会出现根结点平衡因子是 2 和- 2 的两种失衡情况, 此时需要采取适 当的方法对其进行调整, 使之平衡。结合学习实践, 给出了绘制平衡二叉排序树的巧妙 方法, 辅以实例加以说明。
(总
study practice, gives a skillful way to draw the balance binary tree, the application of the


rules is demonstrated by several examples.

Keywords : Balance Factor; Balance Binary Tree; Data Structure
第三步: 插入结点 k; 第四步: 插入结点 m; 第 五 步 : 对 由 结 点 p,k,m 构 成 的 树 , 遵 循 根 结 点 平衡因子是 2 的情况进行调整; 第六步: 插入结点 l; 第七步: 遵循根结点平衡因子是- 2 的情况对第 六步形成的失衡二叉树排序进行调整; 第八步: 插入结点 b; 第九步: 对有结点 i,e,b 构成的树, 遵循根结点平 衡因子是 2 的情况进行调整, 得到所要绘制的 AVL 树。
2 失衡二叉排序树
平衡因子为 1 的结点作为根结点; 第二步: 把平衡因子为 1 的结点的左右子树采用 相邻赋予, 即若它的左边有结点, 则把左子树给予它 左边的结点, 作为其右子树, 没有则保持。同理, 若它 的右边有结点, 则把的右子树给予它右边的结点, 作 为其左子树, 没有则保持; 第三步: 经第二步后, 以原平衡因子为 2 的结点
5 结语
熟练掌握平衡二叉排序树的生成, 不仅可以提高 算法的有效性, 提高程序的运行效率, 还可以使在竞 争激烈的入学考试中处于有利地位。
参考文献 [1]耿国华等. 数据结构— ——C 语言描述. 西安: 西安电子科
技大学出版社, 2002, 2 [2]苏仕华. 数据结构与算法. 合肥: 中国科学技术大学出版
则现根结点的左子树或右子树由原平衡因子为 1 的 现
结点的左子树或右子树替代。

图 1 和图 2 调整后恢复平衡的图如图 3 和图 4。 计
当给一棵平衡二叉树的左子树插入一个新结点,
( 2) 实例解析

致使其失去平衡。此时出现两种情况: ①在左子树的 左 子 树 上 插 入 一 个 新 结 点 N, 即 LL 型 ( Left,Left) , 如





(总
图8
图9


( 1) 调整方法

第一步: 以平衡因子为- 1 的结点作为根结点;

第二步: 把平衡因子为- 1 的结点的左右子树采


!" MO D E R N C OMP U T E R 2007.10
图 10
图 11
( 2) 实例解析 如图 12 所示是一棵平衡二叉排序树, 当插入一 个新结点 70 后, 失去平衡, 如图 13, 经过上面的调整 方法得到一棵平衡二叉排序树如图 14 所示。
作为其左子树, 没有则保持;
第三步: 经第二步后, 以原平衡因子为- 2 的结点
及其子树作为根结点的右子树, 以原根结点的左结点
图3
图4
及其子树作为现根结点的左子树。在此过程中, 如果
原平衡因子为- 1 的结点, 它的左边或右边没有结点,
则现根结点的左子树或右子树由原平衡因子为 1 的
结点的左子树或右子树替代。
3.2 根结点平衡因子是- 2 的失衡情况
当给一棵平衡二叉树的右子树插入一个新结点 N, 致使其失去平衡。此时出现两种情况: ①在右子树 的 右 子 数 上 插 入 一 个 新 结 点 N, 即 RR 型 ( Right, Right) , 如图 8 所示;②在右子树的左子树上插入一个 新结点 N, 即 RL 型( Right,Left) ,如图 9 所示。
实践与经验
4 综合运用
题 : 按 下 列 次 序 输 入 关 键 字 : e,i,p,k,m,l,b,试 画 出 AVL 树的构造与调整过程。【山东大学 1992 年硕士研 究生入学试题】
解: 详细解答过程如图:
过程描述: 第二步: 遵循根结点平衡因子是- 2 的 情况对第一步形成的失衡二叉排序树进行调整;
社, 2004, 1 [3]陈守孔等. 算法与数据结构考研试题精析. 北京: 机械工
业出版社, 2004, 10
Dra wing Ba la nce Bina ry Tre e
PAN Zhao- qing1 , ZHOU Cai- gen2

(1. College of Information Science and Technology, College of Huanghai, Yancheng Normal College, Yancheng 224002;


2. College of Information Science and Technology, Yancheng Normal College, Yancheng 224002)


Abs tract: For a binary tree of unbalance, there appears the balance factor of crunode of root is 2 and - 2 and should take proper method to adjust so as to make it balance. According to the

作者简介: 潘兆庆( 1986- ) , 男, 江苏南京人, 研究方向为计算机免疫、人工智能

MO D E R N C OMP U T E R 2007.10 !" )
实践与经验
用相邻赋予, 即若它的左边有结点, 则把左子树给予
它左边的结点, 作为其右子树, 没有则保持。同理, 若
它的右边有结点, 则把的右子树给予它右边的结点,
概念: 当给一棵平衡二叉排序树插入一个结点
及其子树作为根结点的右子树, 以原根结点的左结点
时, 出现绝对值大于 1 的平衡因子, 此时称平衡二叉
及其子树作为现根结点的左子树。在此过程中, 如果
排序树失去平衡。
原平衡因子为 1 的结点, 它的左边或右边没有结点,
3 平衡二叉排序树失衡情况及其调整方法 3.1 根结点平衡因子是2 的失衡情况


MO D E R N C OMP U T E R 2007.10 !" )
相关文档
最新文档