二叉查找树:插入和有序输出
二叉查找树是常用的数据结构
- 二叉查找树根结点比左儿子大,比右儿子小(或等)
- 以任意结点为根节点的子树也满足上述规律
结点数为n,深度为h 的二叉查找树的操作
以下操作时间复杂度均为O(h)
因为这些操作都是逐层下降,每层只停留一次
1. 元素值查找
2. 插入元素(该操作将且仅将新元素插入为叶节点)
3. 删除元素
二叉树遍历所有元素有序输出的复杂度为O(n)
因为从一个结点到下一个结点的时间间隔是常数
结点数n和深度h 的关系涉及到平衡树
lg(n)≤h≤n
可以用二叉查找树实现排序
如本例所演示,逐个插入待排序元素,最后的输出结果是数组中的序列按升序打印
该种方法若输入随机化之后,得到接近二叉平衡树情况下,排序时间复杂度也是O(nlg(n))
二叉树插入和遍历的实现
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef int elemtype;
struct bstreeNode
{
elemtype data;
bstreeNode * left;
bstreeNode * right;
};
void insert(bstreeNode * & r, elemtype val)
{
bstreeNode * p = r;
bstreeNode * pp = NULL;
while(p != NULL)
{
pp = p;
if (val >= p->data)
{
p = p->right;
}
else
{
p = p->left;
}
}
if(pp != NULL)
{
bstreeNode * pi = new bstreeNode;
pi -> data = val;
pi -> left = NULL;
pi -> right = NULL;
if (pp -> data <= val)
{
pp -> right = pi;
}
else
{
pp -> left = pi;
}
}
}
bstreeNode * cretree(const vector<elemtype> & arr)
{
bstreeNode * root = new bstreeNode;
if( arr.size()>0 )
{
root -> data = arr.at(0);
root -> left = NULL;
root -> right = NULL;
}
for(int i=1; i<arr.size(); i++)
{
insert(root, arr.at(i));
}
return root;
}
void destree(bstreeNode * & r)
{
if( r != NULL)
{
destree( r -> left );
destree( r -> right );
}
delete r;
}
void mttree(bstreeNode * root) //traversal tree
{
if(root != NULL)
{
if( root -> left != NULL)
{
mttree( root -> left);
}
cout<< root->data <<" ";
if ( root -> right != NULL)
{
mttree( root -> right);
}
}
}
int main()
{
elemtype arr[] = {4, 52, 26, 4, 8, 1, 15, 3, 27, 108};
vector<elemtype> vec(arr, arr+sizeof(arr)/sizeof(elemtype));
bstreeNode * root = cretree(vec);
mttree(root);
cout<<endl;
destree(root);
return 0;
}
- debug 过程中发现 !r 和 r != NULL 效果不一样,值得注意
- insert 操作中原本使用的也是递归查找到对应的叶结点,同时开辟空间赋值插入:
void insert(bstreeNode * & r, elemtype val)
{
bstreeNode * p = r;
if(p == NULL)
{
bstreeNode * p = new bstreeNode;
p -> data = val;
p -> left = NULL;
p -> right = NULL;
}
if(val >= p -> data )
{
p = p -> right;
insert(pr, val);
}
else
{
p = p -> left;
insert(pl, val);
}
}
该方法debug 过程中最多只能构建两个结点. 原因:父子关系丢失,树不能连接起来,因此每次插入最多只有2个结点. 需要在insert()函数中添加一个参数,指向当前子树根的父结点.
改用迭代之后会更接近 insert 的表达习惯,代码如上: 先找到插入点的位置,再对位置进行操作.