额,本文主要是对平衡二叉树进行实现,以及测试节点的插入,删除,查找操作的效率分析。下面直接上代码:
头文件avltree.h:
#ifndef _AVLTREE_H_
#define _AVLTREE_H_
#include <iostream>
using namespace std;
//平衡与否标志
#ifndef LH //左子树高1
#define LH +1
#endif
#ifndef EH //子树平衡
#define EH 0
#endif
#ifndef RH //右子树高1
#define RH -1
#endif
struct node_t //节点值定义,包括key值与value值
{
node_t():key(0), value(0)
{
}
node_t(int key_, int value_):
key(key_),
value(value_)
{
}
int key;
int value;
};
struct avl_node_t //平衡二叉树中,节点信息定义,包括上述节点值,以及指针,平衡标志
{
avl_node_t(int key_, int value_)
{
node.key = key_;
node.value = value_;
balance = EH;
lchild = NULL;
rchild = NULL;
}
node_t node;
int balance;
avl_node_t* lchild;
avl_node_t* rchild;
};
class avltree_t //平衡二叉树类
{
public:
typedef avl_node_t* avl_node_ptr_t;
public:
avltree_t()
{
m_root = NULL;
m_tall = false;
m_short = false;
}
~avltree_t()
{
if (NULL != m_root)
{
destroy_tree();
m_root = NULL;
}
}
void show_pre(); //先序遍历接口
void show_mid(); //中序遍历接口
int insert_node(node_t node_); //插入节点,实际调用下一个插入函数
int insert_node(avl_node_ptr_t &root_, node_t node_);
void balance_left(avl_node_ptr_t &root_); //左子树平衡调节
void balance_right(avl_node_ptr_t &root_); //右子树平衡调节
void rotate_left(avl_node_ptr_t &root_); //左旋操作
void rotate_right(avl_node_ptr_t &root_); //右旋操作
int avldelete_node(int key_); //删除key_节点
void delete_node(avl_node_ptr_t &root_); //删除根节点
void delete_balance_left(avl_node_ptr_t &root_); //删除后左子树平衡调节
void delete_balance_right(avl_node_ptr_t &root_); //删除后右子树平衡调节
int search_value(int key_); //查找key_节点接口
void destroy_tree(); //销毁树接口
private:
void show_pre_i(avl_node_ptr_t root_); //先序遍历实现
void show_mid_i(avl_node_ptr_t root_); //中序遍历实现
void visit_value_i(avl_node_ptr_t root_);
int search_value_i(avl_node_ptr_t root_, int key_); //查找实现
int avldelete_node_i(avl_node_ptr_t &root_, int key_);//删除实现
void destroy_tree_i(avl_node_ptr_t &root_); //销毁实现
private:
//! 平衡二叉树根结点
avl_node_ptr_t m_root;
//! 当插入结点便树变高时置为true
bool m_tall;
//! 当删除结点导致树不平衡时置为true
bool m_short;
};
#endif
从以上代码中,可以看出,平衡二叉树的构造过程,就是不断的插入过程中,检查树高变化,如有,则查看是何位置,再判断是否有必要进行调整,而根据要调整的子树的不同,以及需要调整的子树结构的不同,所选择的旋转操作也不同,包括左旋与右旋。
节点的查找,由于平衡二叉树也是二叉搜索树,因此,左子树的所有key值都小于根结点,且右子树的所有key值都大于根结点。因此,查的时间复杂度为,log(n)。
节点的删除,则需要先找到,再删除,然后判断删除后对当前树的影响,再向上分析对更大的树的影响,如有,则进行必要的调整,本文代码的详细实现将在下一篇博文中列出,以下先给出测试效率代码。
#include <sys/time.h> #include <time.h> #include <stdlib.h> #include "avltree.h" #ifndef SIZE #define SIZE 100000 #endif int main() { avltree_t avltree; srand((unsigned)time(NULL)); node_t node; //! 对插入效率的测试 for (int i = 1; i <= SIZE; i++) { node.key = i; node.value = rand(); avltree.insert_node(node); } //! 对查找效率的测试 cout << avltree.search_value(rand() % SIZE + 1) << endl; //! 对删除效率的测试 for (int i = 1; i <= SIZE; i++) { //cout << i << endl; avltree.avldelete_node(i); } //! 对于上述三种测试,测试哪种则将之写入以下代码测试处,以时间为标准测试性能 struct timeval before, after; gettimeofday(&before, NULL); //! 插入测试代码处 gettimeofday(&after, NULL); long int time_use; time_use = (after.tv_sec - before.tv_sec) * 1000000 + (after.tv_usec - before.tv_usec); cout << time_use << endl; return 0; }
测试结果如图片所示: