理论解释:
http://www.cnblogs.com/skywang12345/p/3576328.html
很详细。不过函数实现略微复杂,不容易看懂。
函数实现:
http://www.cnblogs.com/elleniou/archive/2012/05/03/2480042.html
简单清晰。不过注释比较少,要认真看一会。
本人所用的测试代码是基于第二个链接,详细的步骤解释,参看代码
一、创建
#include "stdafx.h"
#include <iostream>
using std::cout;
using std::cin;
using std::endl;
struct tree // 其实该结构体应该是节点(Node,很多参考资料都有Node结构体)。但是理解为子树更容易理解操作过程,所以定义为tree是别有用心的
{
int key; // 关键字,用于排序和查找
tree* left; // 设置为指针确有妙处!
tree* right;
};
// * 二叉查找树的类
class BTree // 这个BTree的B是binary search tree的B
{
public:
tree* root;
BTree(){ root = NULL; } // 初始化
void create_bstree(int);
void printTree(tree* subtree);
};
// * 类函数的实现
void BTree::create_bstree(int key)
{
tree* new_node = new tree; // 使用new申请内存空间
new_node->key = key; // 将新输入的数值包装成一个子树
new_node->left = new_node->right = NULL;
/* 判断当前的数是不是空树 */
if( root == NULL )
root = new_node;
else // 不是空树则开始比较数值,判断新输入 new_node 的合适位置
{
tree* back = NULL;
tree* current = root; // 指针current指向了root,current的修改都会影响到root,两个指针都是指向这个地址
//(不是两指针相等而是两个指针指向的内容相等)
while(current!=NULL) // 判断new_node需要放置的节点(此刻还是叶子)
{
back = current; // 控制循环次数
if(current->key > key) // 应该是左侧
current = current->left;
else
current = current->right;
}
// 获得
if(back->key >key) // 决定new_node的左右位置
back->left = new_node;
else
back->right = new_node;
}
}
// * 显示函数(有些不太直观,不过可以证明,树已经建立)
void printTree(tree* subtree)
{
if(subtree->right != NULL && subtree->left != NULL)
{
cout<<subtree->key<<endl;
if(subtree->right->key == NULL)
cout<<"右儿子 = NULL"<<endl;
else
cout<<"右儿子"<<subtree->right->key<<endl;
if(subtree->left->key == NULL)
cout<<"左儿子 = NULL"<<endl;
else
cout<<"左儿子"<<subtree->left->key<<endl;
printTree(subtree->right);
printTree(subtree->left);
}
}
int _tmain()
{
BTree A;
int array[]={7,4,2,3,15,35,6,45,55,20,1,14,56,57,58};
int k;
k = sizeof(array)/sizeof(array[0]);
cout<<"二叉树顺序: "<<endl;
for(int i=0;i<k;i++)
{
cout<<array[i]<<" ";
A.create_bstree(array[i]);
} cout<<endl;
printTree(A.root); // 是使用根节点来打印
return 0;
}
在学习二叉树的时候,我最关注的是这个数据结构是怎么存在的,数据按照规则存放在哪。
按照我的理解,数据本身无序,所以建立数据结构,需要给数包装。这个包装就是Tree结构体。
包装以后的数据,带有其他的参数变量(指针居多),用于支撑这个结构。(方便后续的数据处理)
在内存中,把数据包装,用指针建立两两间关系,数据结构就好了。
tip:
其实,显示函数的优劣很重要。但是写不出来好的也没关系。我们可以在debug下设置断点,一步步查看root里面数据的变化,就可以看到数据的层次。
二、寻找函数
寻找函数(声明部分)
// * 二叉查找树的类
class BTree
{
public:
tree* root;
BTree(){ root = NULL; }
void create_bstree(int);
void printTree(tree*); // 可以只给出类型
int getDepth(tree*,int);
void setDepth(tree*);
tree* find(tree* dtree, int x);
private:
int depth;
};
寻找函数(实现部分)
// * 给元素赋值深度(可以放在create_bstree中吗?思路就不清晰了。)
void BTree::setDepth(tree* Dtree)
{
if(Dtree == NULL)
cout<<"树为空!"<<endl;
else
{
if(Dtree->left != NULL ) // 实际上函数是利用父节点来设置子节点的深度
{
Dtree->left->depth = Dtree->depth + 1;
setDepth(Dtree->left);
}
if(Dtree->right != NULL )
{
Dtree->right->depth = Dtree->depth + 1;
setDepth(Dtree->right);
}
}
}
// * 查询元素,返回其父(子树的root)
// 逻辑解释:最大的困惑是if(dtree->key == x && dtree != NULL)似乎是更合适的条件,相等,而且非空。
// 其实不然。相等自然没错,但是“&& 非空”的条件,想想当迭代一直到树叶的时候会怎么样?
// 条件不成立,去执行 dtree->key,这时候就会发生内存读取错误。因为这时候的dtree是NULL!
/*
tree* BTree::find(tree* dtree, int x)
{
if(dtree->key == x || dtree == NULL)
return dtree;
else if(dtree->key < x) //往右寻找
return find(dtree->right,x);
else // 往左寻找
return find(dtree->left,x);
}
*/
// 改进后的,增加外来元素的判断,外来元素返回NULL
tree* BTree::find(tree* dtree, int x)
{
if(dtree->key == x)
return dtree;
else if(dtree->key < x) //往右寻找
{
if(dtree->right != NULL)
return find(dtree->right,x);
else
return NULL;
}
else // 往左寻找
{
if(dtree->left != NULL)
return find(dtree->left,x);
else
return NULL;
}
}
// * 查询深度(要先执行setDepth() )
int BTree::getDepth(tree* dtree, int x)
{
tree* result = BTree::find(dtree,x);
if(result != NULL)
return result->depth;
else
return -1; // 没有这个元素
}
调用示例
cout<<"100的深度是"<<A.getDepth(A.root,55)<<endl;
同样可以在
三、三种遍历
可以参看连接2
1.先序遍历
2.中序遍历
3.后序遍历