版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zxt_1/article/details/85212522
文章目录
1.二分查找法变种(要查找的元素有多个)
实现
// 二分查找法, 在有序数组arr中, 查找target
// 如果找到target, 返回第一个target相应的索引index
// 如果没有找到target, 返回比target小的最大值相应的索引, 如果这个最大值有多个, 返回最大索引
// 如果这个target比整个数组的最小元素值还要小, 则不存在这个target的floor值, 返回-1
template<typename T>
int floor(T arr[], int n, T target){
// 寻找比target小的最大索引
int l = -1, r = n-1;
while( l < r ){
int mid = l + (r-l+1)/2;
if( arr[mid] >= target )
r = mid - 1;
else
l = mid;
}
assert( l == r );
// 如果该索引+1就是target本身, 该索引+1即为返回值
if( l + 1 < n && arr[l+1] == target )
return l + 1;
// 否则, 该索引即为返回值
return l;
}
// 二分查找法, 在有序数组arr中, 查找target
// 如果找到target, 返回最后一个target相应的索引index
// 如果没有找到target, 返回比target大的最小值相应的索引, 如果这个最小值有多个, 返回最小的索引
// 如果这个target比整个数组的最大元素值还要大, 则不存在这个target的ceil值, 返回整个数组元素个数n
template<typename T>
int ceil(T arr[], int n, T target){
assert( n >= 0 );
// 寻找比target大的最小索引值
int l = 0, r = n;
while( l < r ){
// 使用普通的向下取整即可避免死循环
int mid = l + (r-l)/2;
if( arr[mid] <= target )
l = mid + 1;
else // arr[mid] > target
r = mid;
}
assert( l == r );
// 如果该索引-1就是target本身, 该索引+1即为返回值
if( r - 1 >= 0 && arr[r-1] == target )
return r-1;
// 否则, 该索引即为返回值
return r;
}
2.二分搜索树
2.1 定义(与堆区别)
2.2 插入
实现
// 向二分搜索树中插入一个新的(key, value)数据对
void insert(Key key, Value value){
root = insert(root, key, value);
}
// 向以node为根的二分搜索树中, 插入节点(key, value)
// 返回插入新节点后的二分搜索树的根
Node* insert(Node *node, Key key, Value value){
if( node == NULL ){
count ++;
return new Node(key, value);
}
if( key == node->key )
node->value = value;
else if( key < node->key )
node->left = insert( node->left , key, value);
else // key > node->key
node->right = insert( node->right, key, value);
return node;
}
2.3 查找(contain、search)
// 查看二分搜索树中是否存在键key
bool contain(Key key){
return contain(root, key);
}
// 查看以node为根的二分搜索树中是否包含键值为key的节点
bool contain(Node* node, Key key){
if( node == NULL )
return false;
if( key == node->key )
return true;
else if( key < node->key )
return contain( node->left , key );
else // key > node->key
return contain( node->right , key );
}
// 在二分搜索树中搜索键key所对应的值。如果这个值不存在, 则返回NULL
Value* search(Key key){
return search( root , key );
}
// 在以node为根的二分搜索树中查找key所对应的value
// 若value不存在, 则返回NULL
Value* search(Node* node, Key key){
if( node == NULL )
return NULL;
if( key == node->key )
return &(node->value);
else if( key < node->key )
return search( node->left , key );
else // key > node->key
return search( node->right, key );
}
2.4 删除
删除最小值
实现
// 删除掉以node为根的二分搜索树中的最小节点
// 返回删除节点后新的二分搜索树的根
Node* removeMin(Node* node){
if( node->left == NULL ){
Node* rightNode = node->right;
delete node;
count --;
return rightNode;
}
node->left = removeMin(node->left);
return node;
}
删除最大值
实现
// 删除掉以node为根的二分搜索树中的最大节点
// 返回删除节点后新的二分搜索树的根
Node* removeMax(Node* node){
if( node->right == NULL ){
Node* leftNode = node->left;
delete node;
count --;
return leftNode;
}
node->right = removeMax(node->right);
return node;
}
删除任意值
实现
// 删除掉以node为根的二分搜索树中键值为key的节点
// 返回删除节点后新的二分搜索树的根
Node* remove(Node* node, Key key){
if( node == NULL )
return NULL;
if( key < node->key ){
node->left = remove( node->left , key );
return node;
}
else if( key > node->key ){
node->right = remove( node->right, key );
return node;
}
else{ // key == node->key
if( node->left == NULL ){
Node *rightNode = node->right;
delete node;
count --;
return rightNode;
}
if( node->right == NULL ){
Node *leftNode = node->left;
delete node;
count--;
return leftNode;
}
// node->left != NULL && node->right != NULL
Node *successor = new Node(minimum(node->right));
count ++;
successor->right = removeMin(node->right);
successor->left = node->left;
delete node;
count --;
return successor;
}
}
2.5 实现floor、celi
// 寻找key的floor值
// 如果不存在key的floor值(key比BST中的最小值还小), 返回NULL
Key* floor(Key key){
if( count == 0 || key < minimum() )
return NULL;
Node *floorNode = floor(root, key);
return &(floorNode->key);
}
// 在以node为根的二叉搜索树中, 寻找key的floor值所处的节点, 递归算法
Node* floor(Node* node, Key key){
if( node == NULL )
return NULL;
// 如果node的key值和要寻找的key值相等
// 则node本身就是key的floor节点
if( node->key == key )
return node;
// 如果node的key值比要寻找的key值大
// 则要寻找的key的floor节点一定在node的左子树中
if( node->key > key )
return floor( node->left , key );
// 如果node->key < key
// 则node有可能是key的floor节点, 也有可能不是(存在比node->key大但是小于key的其余节点)
// 需要尝试向node的右子树寻找一下
Node* tempNode = floor( node->right , key );
if( tempNode != NULL )
return tempNode;
return node;
}
// 寻找key的ceil值
// 如果不存在key的ceil值(key比BST中的最大值还大), 返回NULL
Key* ceil(Key key){
if( count == 0 || key > maximum() )
return NULL;
Node *ceilNode = ceil(root, key);
return &(ceilNode->key);
}
// 在以node为根的二叉搜索树中, 寻找key的ceil值所处的节点
Node* ceil(Node* node, Key key){
if( node == NULL )
return NULL;
// 如果node的key值和要寻找的key值相等
// 则node本身就是key的ceil节点
if( node->key == key )
return node;
// 如果node的key值比要寻找的key值小
// 则要寻找的key的ceil节点一定在node的右子树中
if( node->key < key )
return ceil( node->right , key );
// 如果node->key > key
// 则node有可能是key的ceil节点, 也有可能不是(存在比node->key小但是大于key的其余节点)
// 需要尝试向node的左子树寻找一下
Node* tempNode = ceil( node->left , key );
if( tempNode != NULL )
return tempNode;
return node;
}
2.6 实现predecessor、successor
// 查找key的前驱
// 如果不存在key的前驱(key不存在, 或者key是整棵二叉树中的最小值), 则返回NULL
Key* predecessor(Key key){
Node *node = search(root, key);
// 如果key所在的节点不存在, 则key没有前驱, 返回NULL
if(node == NULL)
return NULL;
// 如果key所在的节点左子树不为空,则其左子树的最大值为key的前驱
if(node->left != NULL)
return &(maximum(node->left)->key);
// 否则, key的前驱在从根节点到key的路径上, 在这个路径上寻找到比key小的最大值, 即为key的前驱
Node* preNode = predecessorFromAncestor(root, key);
return preNode == NULL ? NULL : &(preNode->key);
}
// 在以node为根的二叉搜索树中, 寻找key的祖先中,比key小的最大值所在节点
// 算法调用前已保证key存在在以node为根的二叉树中
Node* predecessorFromAncestor(Node* node, Key key){
if(node->key == key)
return NULL;
if(key < node->key)
// 如果当前节点大于key, 则当前节点不可能是比key小的最大值
// 向下搜索到的结果直接返回
return predecessorFromAncestor(node->left, key);
else{
assert(key > node->key);
// 如果当前节点小于key, 则当前节点有可能是比key小的最大值
// 向右继续搜索, 将结果存储到tempNode中
Node* tempNode = predecessorFromAncestor(node->right, key);
if(tempNode)
return tempNode;
else
// 如果tempNode为空, 则当前节点即为结果
return node;
}
}
// 查找key的后继
// 如果不存在key的后继(key不存在, 或者key是整棵二叉树中的最大值), 则返回NULL
Key* successor(Key key){
Node *node = search(root, key);
// 如果key所在的节点不存在, 则key没有前驱, 返回NULL
if(node == NULL)
return NULL;
// 如果key所在的节点右子树不为空,则其右子树的最小值为key的后继
if(node->right != NULL)
return &(minimum(node->right)->key);
// 否则, key的后继在从根节点到key的路径上, 在这个路径上寻找到比key大的最小值, 即为key的后继
Node* sucNode = successorFromAncestor(root, key);
return sucNode == NULL ? NULL : &(sucNode->key);
}
// 在以node为根的二叉搜索树中, 寻找key的祖先中,比key大的最小值所在节点
// 算法调用前已保证key存在在以node为根的二叉树中
Node* successorFromAncestor(Node* node, Key key){
if(node->key == key)
return NULL;
if(key > node->key)
// 如果当前节点小于key, 则当前节点不可能是比key大的最小值
// 向下搜索到的结果直接返回
return successorFromAncestor(node->right, key);
else{
assert(key < node->key);
// 如果当前节点大于key, 则当前节点有可能是比key大的最小值
// 向左继续搜索, 将结果存储到tempNode中
Node* tempNode = predecessorFromAncestor(node->left, key);
if(tempNode)
return tempNode;
else
// 如果tempNode为空, 则当前节点即为结果
return node;
}
}