巧绘平衡二叉排序树
- 格式:pdf
- 大小:513.00 KB
- 文档页数:3
二叉树再平衡的方法二叉树再平衡是指在二叉树失衡的情况下,调整二叉树的结构,使其恢复平衡的过程。
二叉树的失衡是指左子树或右子树的深度与另一侧的深度差大于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:⼆叉排序树(⼆叉查找树)前⼏节介绍的都是有关静态查找表的相关知识,从本节开始介绍另外⼀种查找表——动态查找表。
动态查找表中做查找操作时,若查找成功可以对其进⾏删除;如果查找失败,即表中⽆该关键字,可以将该关键字插⼊到表中。
动态查找表的表⽰⽅式有多种,本节介绍⼀种使⽤树结构表⽰动态查找表的实现⽅法——⼆叉排序树(⼜称为“⼆叉查找树”)。
什么是⼆叉排序树?⼆叉排序树要么是空⼆叉树,要么具有如下特点:⼆叉排序树中,如果其根结点有左⼦树,那么左⼦树上所有结点的值都⼩于根结点的值;⼆叉排序树中,如果其根结点有右⼦树,那么右⼦树上所有结点的值都⼤⼩根结点的值;⼆叉排序树的左右⼦树也要求都是⼆叉排序树;例如,图 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);}}⼆叉排序树中插⼊关键字⼆叉排序树本⾝是动态查找表的⼀种表⽰形式,有时会在查找过程中插⼊或者删除表中元素,当因为查找失败⽽需要插⼊数据元素时,该数据元素的插⼊位置⼀定位于⼆叉排序树的叶⼦结点,并且⼀定是查找失败时访问的最后⼀个结点的左孩⼦或者右孩⼦。
平衡二叉树关于树的深度是平衡的,具有较高的检索效率。
平衡二叉树或是一棵空树,或是具有下列性质的二叉排序树:其左子树和右子树都是平衡二叉树,而且左右子树深度之差绝对值不超过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结点即可。
攀枝花学院学生课程设计(论文)题目:二叉排序树与平衡二叉树的实现学生姓名:学号:所在院(系):计算机学院专业:班级:指导教师:职称:年月日攀枝花学院教务处制攀枝花学院本科学生课程设计任务书题目二叉排序树与平衡二叉树的实现1、课程设计的目的1)使学生进一步理解和掌握课堂上所学各种基本抽象数据类型的逻辑结构、存储结构和操作实现算法,以及它们在程序中的使用方法。
2)使学生掌握软件设计的基本内容和设计方法,并培养学生进行规范化软件设计的能力。
3)使学生掌握使用各种计算机资料和有关参考资料,提高学生进行程序设计的基本能力。
2、课程设计的内容和要求(包括原始数据、技术要求、工作要求等)1) (1)以回车('\n')为输入结束标志,输入数列L,生成一棵二叉排序树T;(2)对二叉排序树T作中序遍历,输出结果;(3)计算二叉排序树T查找成功的平均查找长度,输出结果;(4)输入元素x,查找二叉排序树T,若存在含x的结点,则删该结点,并作中序遍历(执行操作2);否则输出信息“无x”;(5)用数列L,生成平衡的二叉排序树BT:当插入新元素之后,发现当前的二叉排序树BT不是平衡的二叉排序树,则立即将它转换成新的平衡的二叉排序树BT;(6)计算平衡的二叉排序树BT的平均查找长度,输出结果。
3、主要参考文献[1]刘大有等,《数据结构》(C语言版),高等教育出版社[2]严蔚敏等,《数据结构》(C语言版),清华大学出版社[3]William Ford,William Topp,《Data Structure with C++》清华大学出版社[4]苏仕华等,数据结构课程设计,机械工业出版社4、课程设计工作进度计划第1天完成方案设计与程序框图第2、3天编写程序代码第4天程序调试分析和结果第5天课程设计报告和总结指导教师(签字)日期年月日教研室意见:年月日学生(签字):接受任务时间:年月日注:任务书由指导教师填写。
课程设计(论文)指导教师成绩评定表题目名称二叉排序树与平衡二叉树的实现评分项目分值得分评价内涵工作表现20% 01 学习态度 6 遵守各项纪律,工作刻苦努力,具有良好的科学工作态度。
⼆叉排序树和平衡树B树的结构有:B-Tree, B-Tree, B*TreeBTree(⼆叉排序树)B-Tree:B树也是⼆叉排序树的变异版本,是N叉的排序树。
M阶BTree的⼏个重要特性1.结点最多含m棵⼦树(指针),m-1个关键字(存的数据,空间)(m >= 2)2.除根节点和叶⼦结点外,其它每个结点⾄少有ceil(m / 2)个⼦节点,ceil向上取整3.若根节点不是叶⼦节点,则⾄少有两棵⼦树。
⼆叉排序树BST,也称⼆叉查找树在⼆叉查找树中,因为中序遍历的顺序是左⼦树,根,右⼦树,⽽在⼆叉排序树中,左⼦树结点值 < 根节点值 < 右⼦树结点值,所以,⼆叉排序树的中序遍历序列是递增的结果。
⼆叉排序树的中序遍历序列⼀定是⼀个递增的有序序列。
对于这棵树,中序遍历序列是:1, 2, 3, 4, 5, 7, 8, 10, 16对于⼆叉排序树⽽⾔,我们最常⽤的操作并不是排序,⽽是查找。
查找操作1.判断⼆叉树是否为空2.⼆叉树若不为空,则查找根节点,若相等则查找成功3.若根节点不相等,则当⼩于根节点则查找左⼦树;当⼤于根结点值时则查找右⼦树。
4.当查找到叶节点仍没查找到相对应的值(判断指针是否为空),则查找失败。
该算法的时间复杂度为O(h)1 BSTNode* BST_Search(BiTree T, ElemType key, BSTNode* &p)2 {3 p = NULL;4while(T != NULL && key != T.data)5 {6if(key < T.data)7 T = T -> lchild;8if(key > T.data)9 T = T -> rchild;10 }11return T;1213 }插⼊若⼆叉排序树为空,则直接插⼊结点若⼆叉排序树⾮空,当值⼩于根节点时插⼊左⼦树;当值⼤于根节点时,插⼊右⼦树,当值等于根节点时不进⾏插⼊。
平衡二叉树构造方法构造平衡二叉树的方法有很多,其中一种绝妙的方法是通过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树进行构造是一种有效的方法来构造平衡二叉树。
它将数据按照升序或者降序排列,选择中间元素作为根节点,然后递归地对左子树和右子树进行构造。
这种方法保证了构造的树是一个平衡二叉树,从而提高了数据的查找、插入和删除等操作的效率。
巧绘平衡二叉排序树
潘兆庆;周彩根
【期刊名称】《现代计算机(专业版)》
【年(卷),期】2007(000)010
【摘要】一棵失衡的二叉树会出现根结点平衡因子是2和-2的两种失衡情况,此时需要采取适当的方法对其进行调整,使之平衡.结合学习实践,给出了绘制平衡二叉排序树的巧妙方法,辅以实例加以说明.
【总页数】3页(P77-79)
【作者】潘兆庆;周彩根
【作者单位】盐城师范学院黄海学院信息科与技术学院,盐城,224002;盐城师范学院信息科学与技术学院,盐城,224002
【正文语种】中文
【中图分类】TP3
【相关文献】
1.平衡二叉排序树的平衡调整简单算法 [J], 张冰川
2.严格平衡二叉排序树类属类 [J], 岑岗;周炳生
3.严格平衡二叉排序树及其构造 [J], 岑岗;周炳生
4.基于旋转的平衡二叉排序树上插入的实现 [J], 曾祥师;王悦;雷甜甜
5.二叉排序树转换成平衡二叉树 [J], 王钢
因版权原因,仅展示原文概要,查看原文内容请购买。