[BinaryTree] 二叉搜索树(二叉查找树、二叉排序树)
二叉查找树(BinarySearch Tree,也叫二叉搜索树,或称二叉排序树BinarySort Tree)或者是一棵空树,或者是具有下列性质的二叉树:
(1)若它的左子树不为空,则左子树上所有结点的值均小于它的根结点的值;
(2)若它的右子树不为空,则右子树上所有结点的值均大于它的根结点的值;
(3)它的左、右子树也分别为二叉查找树。
下面是它的几个重要函数:
插入结点:
【思路1】递归
终止条件(1,2):
1.若插入到一个空树中,则新建结点为根结点,左右孩子置为空,返回true
2.若等于根结点的值,返回false
3.若当前值小于根结点的值,递归左子树,否则递归右子树
1 template<class T> 2 bool BinarySearchTree<T>::InsertNode(BinaryTreeNode<T> * &root, T newpointer) 3 { 4 if (root == NULL) 5 { 6 root = new BinaryTreeNode<T>; 7 root->element = newpointer; 8 root->LeftChild = root->RightChild = NULL; 9 return true; 10 } 11 if (newpointer == root->element) 12 return false; 13 if (newpointer < root->element) 14 return InsertNode(root->LeftChild, newpointer); 15 else 16 return InsertNode(root->RightChild, newpointer); 17 }
【思路2】非递归
1.若二叉树为空,则首先单独生成根结点
2.执行查找算法,找出被插结点的父亲结点
3.判断被插结点是其父亲结点的左、右儿子,并将被插结点作为叶子结点插入
注:新插入的结点总是叶子结点
1 template<class T> 2 bool BinarySearchTree<T>::InsertNode(BinaryTreeNode<T> * &root, T newpointer) 3 { 4 if (root == NULL) 5 { 6 root = new BinaryTreeNode<T>; 7 root->element = newpointer; 8 root->LeftChild = root->RightChild = NULL; 9 return true; 10 } 11 BinaryTreeNode<T> *pointer = root; 12 while(pointer != NULL) 13 { 14 if (newpointer == pointer->element) 15 return false; 16 else if (newpointer < pointer->element) 17 { 18 if(pointer->LeftChild == NULL) 19 { 20 BinaryTreeNode<T>* l = new BinaryTreeNode<T>(newpointer); 21 l->LeftChild = l->RightChild = NULL; 22 pointer->LeftChild = l; 23 return true; 24 } 25 pointer = pointer->LeftChild; 26 } 27 else 28 { 29 if(pointer->RightChild == NULL) 30 { 31 BinaryTreeNode<T>* r = new BinaryTreeNode<T>(newpointer); 32 r->LeftChild = r->RightChild = NULL; 33 pointer->RightChild = r; 34 return true; 35 } 36 pointer = pointer->RightChild; 37 } 38 } 39 }
删除结点:
【思路】删除二叉搜索树中结点要根据删除的位置分情况讨论
1.删除叶子结点
操作:直接删除,更改它的父亲结点的相应指针场为空。
2.删除结点只有左儿子或只有右儿子
操作:将该结点的子树直接接到该结点位置
3.删除结点有两个子结点
(1)合并删除
(2)通过复制进行删除
选取替身(左子树中最大的结点或右子树中最小的结点)替换到删除结点的位置
1 template<class T> 2 void BinarySearchTree<T>::deleteBinarySearchTree(BinaryTreeNode<T>* root, T x) 3 { 4 bool find = false; 5 int flag = 0;//标志要删除的结点是前驱结点pre的左孩子还是右孩子 6 BinaryTreeNode<T> *pre = NULL; 7 while (root && !find) 8 { 9 if (x == root->element) 10 { 11 find = true; 12 } 13 else if (x < root->element) 14 { 15 pre = root; 16 root = root->LeftChild; 17 flag = -1; 18 } 19 else 20 { 21 pre = root; 22 root = root->RightChild; 23 flag = 1; 24 } 25 } 26 if (root == NULL) 27 { 28 cout << "未找到要删除元素" << endl; 29 return; 30 } 31 //此时root为要删除结点 32 33 //要删除结点是叶子结点 34 if (root->isLeaf()) 35 { 36 if (flag == 0) 37 { 38 delete root; 39 root = NULL; 40 } 41 else if (flag == -1) 42 { 43 pre->LeftChild = NULL; 44 delete root; 45 root = NULL; 46 } 47 else 48 { 49 pre->RightChild = NULL; 50 delete root; 51 root = NULL; 52 } 53 } 54 55 //要删除结点具有左右子结点 56 else if (root->LeftChild && root->RightChild) 57 { 58 //复制删除,选取左子树中最大的结点替换 59 BinaryTreeNode<T> *t = root; 60 BinaryTreeNode<T> *s = root->LeftChild; 61 while (s->RightChild) 62 { 63 t = s; 64 s = s->RightChild; 65 } 66 root->element = s->element; 67 68 //此时S只有左孩子,需要连接到它的前驱结点t上 69 if (root == t)//while循环未执行 70 { 71 t->LeftChild = s->LeftChild; 72 } 73 else//while循环已执行 74 { 75 t->RightChild = s->LeftChild; 76 } 77 delete s; 78 s = NULL; 79 } 80 81 else//要删除结点为单支子树根结点 82 { 83 if (flag == 0)//root为根结点 84 { 85 if (root->LeftChild) 86 { 87 pre = root; 88 root = root->LeftChild; 89 delete pre; 90 pre = NULL; 91 } 92 else 93 { 94 pre = root; 95 root = root->RightChild; 96 delete pre; 97 pre = NULL; 98 } 99 } 100 else if (flag == -1)//root为pre的左子树 101 { 102 if (root->LeftChild)//要删除结点只存在左子树 103 { 104 pre->LeftChild = root->LeftChild; 105 delete root; 106 root = NULL; 107 } 108 else//要删除结点只存在右子树 109 { 110 pre->LeftChild = root->RightChild; 111 delete root; 112 root = NULL; 113 } 114 } 115 else//root为pre的右子树 116 { 117 if (root->LeftChild)//要删除结点只存在左子树 118 { 119 pre->RightChild = root->LeftChild; 120 delete root; 121 root = NULL; 122 } 123 else//要删除结点只存在右子树 124 { 125 pre->RightChild = root->RightChild; 126 delete root; 127 root = NULL; 128 } 129 } 130 } 131 }
查找结点:
【思路】分割式查找法:
1.若根结点的关键码等于查找的关键码,成功。
2.否则,若小于根结点的关键码,查其左子树;大于根结点的关键码,查其右子树。
二叉搜索树的高效率在于继续检索时只需查找两棵子树之一。
1 template<class T> 2 BinaryTreeNode<T>* BinarySearchTree<T>::Search(BinaryTreeNode<T>* root, T x) 3 { 4 BinaryTreeNode<T>* current = root; 5 while((NULL != current) && (x != current->element)) 6 { 7 if(x < current->element) 8 current = Search(root->LeftChild,x); 9 else 10 current = Search(root->RightChild,x); 11 } 12 return current; 13 }