1. 二叉搜索树(BST):
-
特征:二叉树key值唯一;左子树key小于根节点的key;右子树的key大于根节点的key;左右子树也为BST。
中序遍历的结果,是key值按照升序排列的列表,则该树为BST。 -
抽象数据类型
搜索,插入,删除的复杂度均为O(logN),//二叉树public派生 //搜索key,从根节点开始,key大根节点右移,key小根节点左移,直到找到key或者根节点变为空。 template<class E,class K> bool BSTree::Search(const K&k, E&e) const{ BSTreeNode* p=root; while(p){ if(k>p->data) p=p->rightchild; else if(k<p->data) p=p->leftchild; else {e=p->data; return true;} return false; } //插入,新插入的节点必定为子叶节点。 //先搜索,若存在,不插入;否则,插入搜寻最后一个的根节点中。 template<class K,class E> BSTree<E,K>& BSTree::insert(const E&e){ BSTreeNode<E>* p=root; BSTreeNode<E>* parent=NULL; while(p){ parent=p; if(e>p->data) p=p->rightchild; else if(e<p->data) p=p->leftchild; else throw BadInput();//找到相同的数。 } BSTreeNode* newnode=new BSTreeNode<E>(e); if (root){//是否是空树? if(e>pp->data) pp->rightchild=newnode; else pp->leftchild=newnode; } else root=newnode; return *this; } //删除 //先看是否存在,存在才进行删除操作。节点为叶节点或者只有一颗子树;否则将节点与直接前驱或者直接后继交换(左子树的最右节点或者右子树的最左节点)转为第一种或者第二种情况,然后进行删除。 BSTree<E,K>& BSTree::Delete(const K&k,E&e){ //先搜索节点是否存在 BSTreeNode<E>* p=root; BSTreeNode<E>* parent=NULL; while(p&&p->data!=k) { parent=p; if(k<p->data) p=p->leftchild; else p=p->rightchild; } if(!p) throwbad(); e=p->data; //如果两个子树都存在,寻找左子树的最右节点(直接前驱)做交换。 if(p->leftchild&&p->rightchild) { BSTreeNode* s=p->leftchild; BSTreeNode* sp=NULL; while(s->rightchild) { sp=s; s=s->rightchild; }//找到了直接前驱为s。 //交换p与其左子树的最右节点。这是怎么交换的????? p->data=s->data; p=s; parent=sp; //已经转化为叶节点或者单继承状态 BSTreeNode<E>* c; if(p->leftchild) c=p->leftchild; else c=p->rightchild; //删除节点p if(p==root) root=c; else { if(p==parent->leftchild) pp->leftchild=c; else pp->rightchild=c; } delete p; return *this; } }
2. AVL树:BST的改进
-
定义:
T为非空二叉树,TL与TR分别为其左子树与右子树,则当TL,TR满足以下条件时,T为AVL树: (1)TL与TR均为AVL树; (2)|HL-HR|<=1,即左子树与右子树的高度相差不能超过1。 因此,空二叉树也为AVL树。
-
特性:
高度:N节点的AVL树高度为O(logN) 存在性:对于每一个N值,都存在一棵AVL树,保证了任何时刻的插入操作都是可行的。 Search复杂度:O(H)=O(logN) Insert复杂度:O(logN) Delete复杂度:O(logN)
-
最坏情况的改进:
高度为H的AVL树最少包含的节点数目:Fh=Fh-1+Fh-2+1----->Fh+1=Fh-1+1+Fh-2+1斐波那契数列。
-
描述及查找、插入、删除思路:
BSTree+平衡因子(balanced factor==H左–H右)
插入算法:插入不平衡:插入节点后只有从根到插入节点路径上的节点平衡因子才会发生改变。设A点为离新插入节点最近的平衡因子为2或-2的节点,则从A到插入节点路径上所有节点原有的bf=0,而A点原有的bf=-1||1。设X点为A类节点中的最后一个。
(1). 插入新节点后,x未变为A—>插入后仍旧保持平衡:bf(x)=0,插入前后以x为根的子树高度不变,新元素插入了较矮的子树。
(2). 插入新节点后,x变为A。则A为X点,且新节点插入了较高的子树。
(3). LL、LR、RL、RR
旋转:节点从左往右的顺序不变,变的是树枝结构。
LL的单旋转如下图,RR的单旋转与此对称。
LR的双旋转如下图,RL的双旋转与此对称。//是真没看懂,待补充。
删除算法:
R0,R1与LL单旋转类似,R(-1)与LR旋转类似。//待补全 //搜索,与BST搜索方法一致,若k大于节点值,则寻找右子树,否则寻找左子树,直到找到或者子树为空。 void Search(const K&k,const E&e); //插入 //按照BST的方法查找插入的节点,若存在则不进行插入。同时记录下最近的bf=1或者-1的节点。 //若不存在这样的节点A,那么插入后不会产生不平衡,从根节点到插入点之间更新bf即可。 //若存在节点A且bf(A)=-1,插入A的左子树或者bf(A)=1插入A的右子树,那么A的平衡因子变为0,树仍旧平衡,更改A到插入点之间的bf即可。 //不平衡则根据相应旋转修改bf。 AVLTree& AVLTree::Insert(const E&e); //删除 //先删除节点,从被删除节点到根节点路径上的每个节点q都进行判断,修正调整 AVLTree& AVLTree::Delete(const E&e)