有趣的算法(五):一文读懂二叉搜索树的插入、删除
零、树的分类
满二叉树:从高到低,除了叶节点外,所以节点左右节点都存在。
完全二叉树:比满二叉树少几个叶节点,从左向右放子节点。
平衡二叉树:空树或者它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树也都是平衡树。
二叉搜索树:空树或者二叉树的所有节点比他的左子节点大,比他的右子节点小。
红黑树:不仅是具有二叉搜索树的属性,还具有平衡树的属性,有序且子树差不超过1,颜色规则:根节点和特殊节点是黑的,红节点的左右子节点是黑的,最重要的是对于每个节点,从该节点到子孙叶节点的所有路径包含相同数目的黑节点。
一、BST
二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。
一棵二叉搜索树是以一棵二叉树来组织的,可以用链表数据结构来表示,其中,每一个结点就是一个对象,一般地,包含数据内容key和指向孩子(也可能是父母)的指针属性。如果某个孩子结点不存在,其指针属性值为空(NIL)。
1. 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
2. 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
3. 任意节点的左、右子树也分别为二叉查找树。
4. 没有键值相等的节点。
BST的一个性质就是中序遍历必须是一个(严格)递增的序列,也就是满足全序的性质。
BST的遍历(中序)
前序遍历(根-左-右):ABDGHECKFIJ
中序遍历(左-根-右):GDHBEAKCIJF
后序便利(左-右-根):GHDEBKJIFCA
- bool BSTSearch(TreeNode* root, int val)
- {
- while (root != NULL&&root->val != val)
- {
- if (val < root->val)
- root = root->left;
- else
- root = root->right;
- }
- return root != NULL;
- }
二、BST的插入与删除
1. BST 插入
插入比较简单,跟查找类似,一直往下,比新结点z小就往左,比z大就往右,知道遇到NULL或者NIL,就挂在那个叶子结点上。插入一直是在后面树的底插,所以二叉搜索树的根结点就是第一个插入的结点,而且不能保证这棵树是不是平衡由于二叉搜索树的特殊性质确定了二叉搜索树中每个元素只可能出现一次,所以在插入的过程中如果发现这个元素已经存在于二叉搜索树中,就不进行插入。
- 第一种情况:root为空,直接插入,return true;
- 第二种情况:要插入的元素已经存在,如上面所说,如果在二叉搜索树中已经存在该元素,则不再进行插入,直接return
- 第三种情况:根据搜索找到合适位置
- bool BSTInsert2(TreeNode* &root, int val)
- {
- TreeNode *node = new TreeNode(val);
- if (root == NULL)
- {
- root = node;
- return true;
- }
- if (val == root->val)
- return false;
- if (val < root->val)
- return BSTInsert2(root->left,val);
- return BSTInsert2(root->right, val);
- }
2.BST 删除
二叉搜索树的结点删除比插入较为复杂,总体来说,结点的删除可归结为三种情况:
1、 如果结点z没有孩子节点,那么只需简单地将其删除,并修改父节点,用NIL来替换z;
2、 如果结点z只有一个孩子,那么将这个孩子节点提升到z的位置,并修改z的父节点,用z的孩子替换z;
3、 如果结点z有2个孩子,那么查找z的后继y,此外后继一定在z的右子树中,然后让y替换z。
什么是后继:一个结点x的后继,就是关键字大于x.key的结点中最小的那个,注意这里有两种情况,如果x是有右子树,那就是x的右子树中最小那个,也就是x的右子树的最左那个结点;如果x是没有右子树,那就需要往上找,从x的父结点开始,一直往左上走(对的是左上方向),一直没有路了,那终点的父节点就是x的后继。
对于第3种情况,可以细分为以下三个步骤:
1、找到该节点的右子树中的最左孩子(也就是右子树中序遍历的第一个节点)
2、把它的值和要删除的节点的值进行交换
3、然后删除这个节点即相当于把我们想删除的节点删除了,返回true;
- void deleteHelper(TreeNode* node)
- {
- if (node->left == NULL)
- node = node->right;
- else if (node->right == NULL)
- node = node->left;
- else
- {
- TreeNode *q=node,*l = node->left;
- while (l->right != NULL)
- {
- q = l;
- l = l->right;
- }
- node->val = l->val;
- if (q == node)
- q->left = l->left;
- else
- q->right = l->left;
- }
- }
- bool BSTDelete(TreeNode* root, int val)
- {
- if (root == NULL)
- return false;
- if (root->val > val)
- return BSTDelete(root->left, val);
- if (root->val < val)
- return BSTDelete(root->right, val);
- deleteHelper(root);
- return true;
- }
参考文章: