二叉搜尋樹及判斷一棵樹是否平衡
阿新 • • 發佈:2019-02-04
二叉搜尋樹的特點:
1. 每個節點都有一個作為搜尋依據的關鍵碼(key),所有節點的關鍵碼互不相同。
2. 左子樹上所有節點的關鍵碼(key)都小於根節點的關鍵碼(key)。
3. 右子樹上所有節點的關鍵碼(key)都大於根節點的關鍵碼(key)。
4. 左右子樹都是二叉搜尋樹。
一棵二叉搜尋樹如下圖:
平衡二叉樹的特點:
左右子樹的高度差<=1
無法達到絕對平衡是因為:如果一棵二叉樹只有兩個節點,則高度差永遠差1。
#pragma once
#include<iostream>
#include<stack>
using namespace std;
template <class K, class V>
struct BinarySearchTreeNode
{
K _key;
V _value;
BinarySearchTreeNode<K, V>* _left;
BinarySearchTreeNode<K, V>* _right;
BinarySearchTreeNode(K& k, V& v)
:_key(k)
, _value(v)
, _left(NULL )
, _right(NULL)
{}
};
template <class K, class V>
class BinarySearchTree
{
typedef BinarySearchTreeNode<K, V> Node;
public:
BinarySearchTree()
: _root(NULL)
{}
bool Insert(K key, V val)
{
if (_root == NULL)
{
_root = new Node(key, val);
return true;
}
Node *cur = _root;
Node *prev = NULL; //儲存cur的前一個節點
while (cur)
{
if (key < cur->_key)
{
prev = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
prev = cur;
cur = cur->_right;
}
else //已經存在
return false;
}
Node *node = new Node(key, val);
if (key < prev->_key)
prev->_left = node;
else
prev->_right = node;
return true;
}
Node *Find(const K& key)
{
Node *cur = _root;
while (cur)
{
if (key < cur->_key)
cur = cur->_left;
else if (key > cur->_key)
cur = cur->_right;
else //找到
return cur;
}
return NULL;
}
bool Remove(const K& key)
{
if (_root == NULL)
return false;
if (_root->_left == NULL && _root->_right == NULL)
{
delete _root;
_root = NULL;
return true;
}
Node *cur = _root;
Node *parent = NULL;
while (cur)
{
if (key < cur->_key)
{
parent = cur;
cur = cur->_left;
}
else if (key > cur->_key)
{
parent = cur;
cur = cur->_right;
}
else //找到要刪除的key
{
//1、cur的左孩子為空
if (cur->_left == NULL)
{
if (cur != _root)
{
if (parent->_left == cur) //判斷cur在parent的左邊還是右邊
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
else //刪除節點為跟節點並且左子樹為空
_root = cur->_right;
}
//2、cur的右孩子為空或左右都為空
else if (cur->_right == NULL)
{
if (cur != _root)
{
if (parent->_left == cur) //判斷cur在parent的左邊還是右邊
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
else
_root = cur->_left;
}
//2、cur的左右都不為空
if (cur->_left != NULL && cur->_right != NULL)
{
Node *del = cur; //儲存要刪除的節點
parent = cur;
cur = cur->_right;
while (cur->_left) //找右子樹的最左節點
{
parent = cur;
cur = cur->_left;
}
// 將最左節點的值賦給要刪除的節點
del->_key = cur->_key;
del->_value = cur->_value;
if (cur == parent->_left)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
delete cur;
cur = NULL;
return true;
}
}
return false;
}
bool Insert_R(K& key, V& val)
{
return _Insert_R(_root, key, val);
}
bool Find_R(const K& key)
{
return _Find_R(_root, key);
}
bool Remove_R(const K& key)
{
return _Remove_R(_root, key);
}
void Inorder()
{
_Inorder(_root);
}
bool Isbalance()
{
int depth = 0;
return _Isbalance(_root,depth);
}
int Heigh()
{
return _Height(_root);
}
protected:
//用後序遍歷的方式遍歷整課二叉樹,在遍歷到某一節點之後根據它左右節點的深度
//判斷當前節點是否平衡,再計算當前節點的深度。知道遍歷到根節點
bool _Isbalance(Node*& root, int& depth)
{
if (root == NULL)
{
depth = 0;
return true;
}
int left = 0;
int right = 0;
if (_Isbalance(root->_left, left) && _Isbalance(root->_right, right))
{
if (abs(left - right) <= 1)
{
depth = (left > right ? left + 1 : right + 1);
return true;
}
}
return false;
}
bool _Insert_R(Node *&root, K& key, V& val)
{
if (root == NULL)
{
root = new Node(key, val);
return true;
}
if (key < root->_key)
return _Insert_R(root->_left, key, val);
else if (key > root->_key)
return _Insert_R(root->_right, key, val);
else
return false;
}
bool _Find_R(Node *&root, const K& key)
{
if (root == NULL)
return false;
if (key < root->_key)
return _Find_R(root->_left, key);
else if (key > root->_key)
return _Find_R(root->_right, key);
else
return true;
}
bool _Remove_R(Node *&root, const K& key)
{
if (root == NULL)
return false;
if (key < root->_key)
return _Remove_R(root->_left, key);
else if (key > root->_key)
return _Remove_R(root->_right, key);
else
{
Node *del = root;
if (root->_left == NULL)
root = root->_right;//利用遞迴的特點
else if (root->_right == NULL)
root = root->_left;
else
{
Node *parent = root;
Node *cur = root;
cur = cur->_right;
while (cur->_left)
{
parent = cur;
cur = cur->_left;
}
root->_key = cur->_key;
root->_value = cur->_value;
del = cur;
if (parent->_left == cur)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
delete del;
del = NULL;
return true;
}
}
int _Height(Node *&root)
{
if (root == NULL)
return 0;
int left = _Height(root->_left);
int right = _Height(root->_right);
return (left > right) ? left + 1 : right + 1;
}
//重複遍歷,低效
bool _Isbalance(Node*& root)
{
if (root == NULL)
return true;
int left = _Height(root->_left);
int right = _Height(root->_right);
if (abs(left - right) > 1)
return false;
return _Isbalance(root->_left) && _Isbalance(root->_right);
}
void _Inorder(Node* root)
{
//stack<Node*> s;
//Node *cur = root;
//while (cur || !s.empty())
//{
// while (cur)
// {
// s.push(cur);
// cur = cur->_left;
// }
// if (!s.empty())
// {
// Node* top = s.top();
// cout << top->_key << " ";
// s.pop();
// cur = top->_right;
// }
//}
//cout << endl;
if (root == NULL)
return;
if (root)
{
_Inorder(root->_left);
cout << root->_key << " ";
_Inorder(root->_right);
}
}
private:
Node *_root;
};
void Test1()
{
int a[] = { 4, 5, 6, 2, 1, 3 };
BinarySearchTree<int, int> bst;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
bst.Insert_R(a[i], i);
}
bst.Inorder();
bst.Find_R(9);
bst.Find_R(10);
/*bst.Remove_R(1);
bst.Inorder();
bst.Remove_R(7);
bst.Inorder();*/
cout << "Isbalabce ? :" << bst.Isbalance() << endl;
}