833系列——二叉排序树
考纲中,二叉排序树在“查找”章节,要求为:二叉排序树及其基本操作。
其基本操作有:查找操作,插入操作,删除操作
一:定义
二叉排序树(Binary Sort Tree),又称二叉查找树,它是一颗空树,或者是具有以下性质的二叉树:
若它的左子树不空,则左子树上所有结点的值均小于它的根节点的值。
若它的右子树不空,则右子树上所有结点的值均大于它的根节点的值。
它的左右子树也都是二叉排序树
二:首先定义一个二叉树的结构
1 struct BSTree 2 { 3 int data; 4 BSTree *lchild, *rchild; 5 BSTree(int d = 0, BSTree *l = NULL, BSTree *r = NULL) 6 { 7 data = d; 8 lchild = l; 9 rchild = r; 10 } 11 };
三:建立一个二叉排序树
二叉排序树的建立,其实就是由一个空树,一个一个的插入数据形成的,也就是需要插入操作
而在插入操作中,我们需要找到插入数据合适的位置,这里又可以看做是查找操作
插入操作有递归和循环两种写法
循环写法:
void insertTree1(BSTree* &root, int key) { if(root == NULL) { BSTree *s = new BSTree(key); root = s; return; } BSTree *t = root; while(t->data != key) { if(key > t->data && t->rchild != NULL) t = t->rchild; else if(key < t->data && t->lchild != NULL) t = t->lchild; else if(key > t->data && t->rchild == NULL) { BSTree *s = new BSTree(key); t->rchild = s; } else if(key < t->data && t->lchild == NULL) { BSTree *s = new BSTree(key); t->lchild = s; } } }
递归写法:
void insertTree2(BSTree* &root, int key) { if(root == NULL) { BSTree *s = new BSTree(key); root = s; return; } if(key > root->data) insertTree2(root->rchild, key); else insertTree2(root->lchild,key); }
查找操作由插入操作简单修改得到,不再上代码
四:删除操作(重点)
删除节点有三种情况:
要删除的点为叶子节点,直接删除即可;
要删除的点只有左子树,或只有右子树,删除节点后,将左子树或右子树整体移动到被删除节点的位置即可;
要删除的节点即有左子树,又有右子树;
第一、二种情况可以合并为第二种,第三种情况比较复杂
根据二叉排序树的定义,节点删除后,这个位置应该由与它大小相邻的数代替,对于下面这张图:
假设要删除的节点为47,那么能够代替这个位置的就是37和48,可以发现,这两个数都有一个特点,37为47的左子树中的最右子树,48为47的右子树的最左子树
基于此可以这样做:假定每次都用较小的数来代替,也就是37,此时51这边整体就不用动了,只需要将37移动到47的位置,然后将37的整个左子树移动到37原来的位置
代码:
void Delete(BSTree* &node) { if(node->lchild == NULL) { BSTree *temp = node; node = node->rchild; delete(temp); } else if(node->rchild == NULL) { BSTree *temp = node; node = node->lchild; delete(temp); } else //用与该节点临近且小于的点代替 { BSTree *newnode = node->lchild; BSTree *temp = node; while(newnode->rchild != NULL) { temp = newnode; newnode = newnode->rchild; } node->data = newnode->data; if(temp != node) temp->rchild = newnode->lchild; else temp->lchild = newnode->lchild; delete(newnode); } } void DeleteTree(BSTree* &root, int key) { if(root == NULL) return; if(key == root->data) Delete(root); else if(key > root->data) return DeleteTree(root->rchild, key); else return DeleteTree(root->lchild, key); }
五:遍历及测试数据
建好二叉排序树后,使用中序遍历,即可得到一个排好序的数列
void InOrder(BSTree *root) { if(root != NULL) { InOrder(root->lchild); cout << root->data << " "; InOrder(root->rchild); } }
测试数据
int main() { int a[12] = {29, 36, 62, 88, 58, 47, 35, 73, 51, 99, 37, 93}; BSTree *root = NULL; for(int i=0; i<12; i++) { insertTree2(root, a[i]); } InOrder(root); cout << endl; DeleteTree(root, 47); InOrder(root); return 0; }