目录
1.二分查找法,在有序数组arr中,查找target ~~!!!有序数组!!!~~
1.二分查找法,在有序数组arr中,查找target ~~!!!有序数组!!!~~
二分查找
#include <iostream>
using namespace std;
//!!!!!有序数组
//二分查找,在有序数组arr中,查找target
//!!!!!有序数组
template<typename T>
int binarySearch(T arr[], int n, T target){
//在arr[l....r]之中查找target
int l = 0, r = n-1;
while(l<=r){
//int mid = (l + r)/2;
int mid = l + (r-l)/2;
if( arr[mid] == target ){
return mid;
}
if( arr[mid] < target ){
r = mid - 1;
}
else{
l = mid + 1;
}
}
return -1;
}
int main(){
return 0;
}
2.二分搜索树的查找于插入 不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
#include <iostream>
using namespace std;
/*二分搜索树 不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
*/
template<typename Key, typename Value>
class BST{
private:
struct Node{
Key key;//键值对
Value value;
Node *left;//左右孩子
Node *right;
NOde(Key key, Value value){
this->key = key;
this->value = value;
this->left = this->right = NULL;
}
};
Node *root; //指针
int count;//共有多少节点
public:
BST(){
root = NULL;
count = 0;
}
~BST(){
}
int size(){
return count;
}
int isEmpty(){
return count = 0;
}
int insert(Key key, Value value){
root = insert(root, key, value);
}
bool contain(Key key){
return contain(root,key);
}
/*
search的返回值有3种方案:
1.返回Node,需要暴露Node类型,用于还要了解Node结构,不好
2.返回Value,C++中返回变量不允许为NULL(查找不到节点的时候需要返回NULL),需要结合contain函数尽心预判断,太麻烦也不好
3.最佳方案,返回Value*,指针可以为空,最为理想
*/
Value* search(Key key){
return search( root, key );
}
private:
//向以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
node->right = insert(node->right,key,value);
return node;
}
//查看以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(root->left,key);
else
return contain(root->right,key);
}
//是以node为跟的二叉搜索树中查找key所对定的value
Value* search(Node* node, Key key){
if(node == NUll) return NULL;
if( key == node->key)
return &(node->key);
else if( key < node->key )
return search(root->left,key);
else
return search(root->right,key);
}
}
int main(){
return 0;
}
3.二分搜索树的遍历 深搜 以及层序遍历 广搜
二分搜索树的前中后序遍历
前序遍历:先访问当前节点,再依次递归左右子树。
中序遍历:先访问左子树,在访问自身,再递归访问右子树。
后序遍历:先递归访问左右子树,在访问自身节点。
#include <iostream>
using namespace std;
/*二分搜索树 不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
*/
/*
二分搜索树的前中后序遍历
前序遍历:先访问当前节点,再依次递归左右子树。
中序遍历:先访问左子树,在访问自身,再递归访问右子树。
后序遍历:先递归访问左右子树,在访问自身节点。
*/
template<typename Key, typename Value>
class BST{
private:
struct Node{
Key key;//键值对
Value value;
Node *left;//左右孩子
Node *right;
NOde(Key key, Value value){
this->key = key;
this->value = value;
this->left = this->right = NULL;
}
};
Node *root; //指针
int count;//共有多少节点
public:
//前序遍历
void preOrder(){
preOrder(root);
}
//中序遍历
void inOrder(){
inOrder(root);
}
//后序遍历
void postOrder(){
postOrder(root);
}
//层序遍历
void levelOrder(){
queue<Node*> q;
q.push(root);//入驻根节点
while(!q.empty()){
Node* node = q.front();//每次取出队首元素
q.pop();
cout<<node->ley<<endl;
if(node->left)//如果有左孩子就入队
q.push( node->left);
if(node->right)//如果有右孩子就入队
q.push( node->right);
}
}
private:
//是以node为跟的二叉搜索树前序遍历
void preOrder(Node* node){
if( node != NULL){
cout<<node->key<<endl;
preOrder(node->left);
preOrder(node->right);
}
}
//是以node为跟的二叉搜索树中序遍历
void inOrder(Node* node){
if( node != NULL){
inOrder(node->left);
cout<<node->key<<endl;
inOrder(node->right);
}
}
//是以node为跟的二叉搜索树中序遍历
void postOrder(Node* node){
if( node != NULL){
postOrder(node->left);
postOrder(node->right);
cout<<node->key<<endl;
}
}
void destory(Node* node){
if( node != NULL ){
destory(node->left);
destory(node->right);
delete node;
count--;
}
}
}
int main(){
return 0;
}
4.删除最大值,最小值
删除最小值:
递归向左找到第一个没有左孩子的节点,就是最小值,然后用该节点的右子节点代替当前节点位置。
删除最大值:
递归向右找到第一个没有右孩子的节点,就是最大值,然后用该节点的左子节点代替当前节点位置。
#include <iostream>
#include <queue>
#include <cassert>
using namespace std;
/*二分搜索树 不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
*/
/*
二分搜索树的前中后序遍历
前序遍历:先访问当前节点,再依次递归左右子树。
中序遍历:先访问左子树,在访问自身,再递归访问右子树。
后序遍历:先递归访问左右子树,在访问自身节点。
*/
template<typename Key, typename Value>
class BST{
private:
struct Node{
Key key;//键值对
Value value;
Node *left;//左右孩子
Node *right;
NOde(Key key, Value value){
this->key = key;
this->value = value;
this->left = this->right = NULL;
}
};
Node *root; //指针
int count;//共有多少节点
public:
/*
删除最小值:
递归向左找到第一个没有左孩子的节点,就是最小值,然后用该节点的右子节点代替当前节点位置。
删除最大值:
递归向右找到第一个没有右孩子的节点,就是最大值,然后用该节点的左子节点代替当前节点位置。
*/
//寻找最小的键值
Key minimum(){
assert(count != 0);
Node* minNode = minimim( root );
return minNode->key;
}
//寻找最大的键值
Key maximum(){
assert(count != 0);
Node* maximum = maximum( root );
return maximum->key;
}
//在二叉树中删除最小值所在节点
void removeMin(){
if( root ){
root = removeMin( root );
}
}
//在二叉树中删除最大值所在节点
void removeMax(){
if( root ){
root = removeMax( root );
}
}
}
private:
Node* minimum(Node* node){
if( node->left == NULL)
return node;
return minimum(node->left);
}
Node* maximum(Node* node){
if( node->right == NULL)
return node;
return maximum(node->right);
}
//删除以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->left = removeMax(node->right);
return node;
}
};
int main(){
return 0;
}
5.二分搜索树任意节点的删除
- 如果要删除的元素没有左子树,那么把右子树接上即可,参考removeMin
- 如果要删除的元素没有右子树,那么把左子树接上即可,参考remvoeMax
- 如果要删除的元素左右子树都存在,那么可以拿右子树的最左边的节点(后继)代替删除元素或者拿左子树的最右节点(前驱代替删除元素,事实上,如果将所有元素排好序,任何元素的前一个元素正是位于左子树的最右节点(前驱),后一个元素正是右子树的最左节点(后继)
#include <iostream> #include <queue> #include <cassert> using namespace std; /*二分搜索树 不一定是完全二叉树 每个节点的健值大于左孩子 每个节点的健值小于右孩子 以左右为根的子树仍为二分搜索树 */ template<typename Key, typename Value> class BST{ private: struct Node{ Key key;//键值对 Value value; Node *left;//左右孩子 Node *right; Node(Key key, Value value){ this->key = key; this->value = value; this->left = this->right = NULL; } Node(Node *node){ this->key = node->key; this->value = node->value; this->left = node->left; this->right = node->right; } }; Node *root; //指针 int count;//共有多少节点 public: /* 删除最小值: 递归向左找到第一个没有左孩子的节点,就是最小值,然后用该节点的右子节点代替当前节点位置。 删除最大值: 递归向右找到第一个没有右孩子的节点,就是最大值,然后用该节点的左子节点代替当前节点位置。 */ //寻找最小的键值 Key minimum(){ assert(count != 0); Node* minNode = minimim( root ); return minNode->key; } //寻找最大的键值 Key maximum(){ assert(count != 0); Node* maximum = maximum( root ); return maximum->key; } //在二叉树中删除最小值所在节点 void removeMin(){ if( root ){ root = removeMin( root ); } } //在二叉树中删除最大值所在节点 void removeMax(){ if( root ){ root = removeMax( root ); } } /*二分搜索树节点的删除 1、如果要删除的元素没有左子树,那么把右子树接上即可,参考removeMin 2、如果要删除的元素没有右子树,那么把左子树接上即可,参考remvoeMax 3、如果要删除的元素左右子树都存在,那么可以拿右子树的最左边的节点(后继) 代替删除元素或者拿左子树的最右节点(前驱)代替删除元素,事实上,如果将所有元素排好序, 任何元素的前一个元素正是位于左子树的最右节点(前驱),后一个元素正是右子树的最左节点(后继) */ void remove(Key key){ root = remove( root, key); } } private: Node* minimum(Node* node){ if( node->left == NULL) return node; return minimum(node->left); } Node* maximum(Node* node){ if( node->right == NULL) return node; return maximum(node->right); } //删除以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->left = removeMax(node->right); return node; } 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->right!=NULL && node->right != NULL !!! //新建一个successor结点,将node结点的右结点 的最小值赋予新的结点 Node *successor = new Node(minimum(node->right)); count ++; successor->right = removeMin(node->right); successor->right = node->left; delete node; count --; return successor; } } }; int main(){ return 0; }
完整代码
#include <iostream>
#include <queue>
#include <cassert>
using namespace std;
/*二分搜索树 不一定是完全二叉树
每个节点的健值大于左孩子
每个节点的健值小于右孩子
以左右为根的子树仍为二分搜索树
*/
/*
二分搜索树的前中后序遍历
前序遍历:先访问当前节点,再依次递归左右子树。
中序遍历:先访问左子树,在访问自身,再递归访问右子树。
后序遍历:先递归访问左右子树,在访问自身节点。
*/
template<typename Key, typename Value>
class BST{
private:
struct Node{
Key key;//键值对
Value value;
Node *left;//左右孩子
Node *right;
Node(Key key, Value value){
this->key = key;
this->value = value;
this->left = this->right = NULL;
}
Node(Node *node){
this->key = node->key;
this->value = node->value;
this->left = node->left;
this->right = node->right;
}
};
Node *root; //指针
int count;//共有多少节点
public:
BST(){
root = NULL;
count = 0;
}
~BST(){
destory( root );
}
int size(){
return count;
}
int isEmpty(){
return count = 0;
}
int insert(Key key, Value value){
root = insert(root, key, value);
}
bool contain(Key key){
return contain(root,key);
}
/*
search的返回值有3种方案:
1.返回Node,需要暴露Node类型,用于还要了解Node结构,不好
2.返回Value,C++中返回变量不允许为NULL(查找不到节点的时候需要返回NULL),需要结合contain函数尽心预判断,太麻烦也不好
3.最佳方案,返回Value*,指针可以为空,最为理想
*/
Value* search(Key key){
return search( root, key );
}
//前序遍历
void preOrder(){
preOrder(root);
}
//中序遍历
void inOrder(){
inOrder(root);
}
//后序遍历
void postOrder(){
postOrder(root);
}
//层序遍历
void levelOrder(){
queue<Node*> q;
q.push(root);//入驻根节点
while(!q.empty()){
Node* node = q.front();//每次取出队首元素
q.pop();
cout<<node->ley<<endl;
if(node->left)//如果有左孩子就入队
q.push( node->left);
if(node->right)//如果有右孩子就入队
q.push( node->right);
}
/*
删除最小值:
递归向左找到第一个没有左孩子的节点,就是最小值,然后用该节点的右子节点代替当前节点位置。
删除最大值:
递归向右找到第一个没有右孩子的节点,就是最大值,然后用该节点的左子节点代替当前节点位置。
*/
//寻找最小的键值
Key minimum(){
assert(count != 0);
Node* minNode = minimim( root );
return minNode->key;
}
//寻找最大的键值
Key maximum(){
assert(count != 0);
Node* maximum = maximum( root );
return maximum->key;
}
//在二叉树中删除最小值所在节点
void removeMin(){
if( root ){
root = removeMin( root );
}
}
//在二叉树中删除最大值所在节点
void removeMax(){
if( root ){
root = removeMax( root );
}
}
/*二分搜索树节点的删除
1、如果要删除的元素没有左子树,那么把右子树接上即可,参考removeMin
2、如果要删除的元素没有右子树,那么把左子树接上即可,参考remvoeMax
3、如果要删除的元素左右子树都存在,那么可以拿右子树的最左边的节点(后继)
代替删除元素或者拿左子树的最右节点(前驱)代替删除元素,事实上,如果将所有元素排好序,
任何元素的前一个元素正是位于左子树的最右节点(前驱),后一个元素正是右子树的最左节点(后继)
*/
void remove(Key key){
root = remove( root, key);
}
}
private:
//向以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
node->right = insert(node->right,key,value);
return node;
}
//查看以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(root->left,key);
else
return contain(root->right,key);
}
//是以node为跟的二叉搜索树中查找key所对定的value
Value* search(Node* node, Key key){
if(node == NUll) return NULL;
if( key == node->key)
return &(node->key);
else if( key < node->key )
return search(root->left,key);
else
return search(root->right,key);
}
//是以node为跟的二叉搜索树前序遍历
void preOrder(Node* node){
if( node != NULL){
cout<<node->key<<endl;
preOrder(node->left);
preOrder(node->right);
}
}
//是以node为跟的二叉搜索树中序遍历
void inOrder(Node* node){
if( node != NULL){
inOrder(node->left);
cout<<node->key<<endl;
inOrder(node->right);
}
}
//是以node为跟的二叉搜索树中序遍历
void postOrder(Node* node){
if( node != NULL){
postOrder(node->left);
postOrder(node->right);
cout<<node->key<<endl;
}
}
void destory(Node* node){
if( node != NULL ){
destory(node->left);
destory(node->right);
delete node;
count--;
}
}
Node* minimum(Node* node){
if( node->left == NULL)
return node;
return minimum(node->left);
}
Node* maximum(Node* node){
if( node->right == NULL)
return node;
return maximum(node->right);
}
//删除以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->left = removeMax(node->right);
return node;
}
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->right!=NULL && node->right != NULL !!!
//新建一个successor结点,将node结点的右结点 的最小值赋予新的结点
Node *successor = new Node(minimum(node->right));
count ++;
successor->right = removeMin(node->right);
successor->right = node->left;
delete node;
count --;
return successor;
}
}
};
int main(){
return 0;
}