⑴有且只有一个特殊的称为树的根(Root)结点;
⑵若n>1时,其余的结点被分成为二个互不相交的子集T1,T2,
分别称之为左、右子树,并且左、右子树又都是二叉树。
由此可知,二叉树的定义是递归的。
二叉树在树结构中起着非常重要的作用。因为二叉树结构简单,存储效率高,树的操作算法相对简单,且任何树都很容易转化成二叉树结构。
遍历二叉树(Traversing Binary Tree):是指按指定的规律对二叉树中的每个结点访问一次且仅访问一次。
所谓访问是指对结点做某种处理。如:输出信息、修改结点的值等。
二叉树是一种非线性结构,每个结点都可能有左、右两棵子树,因此,需要寻找一种规律,使二叉树上的结点能排列在一个线性队列上,从而便于遍历。
二叉树的基本组成:根结点、左子树、右子树。若能依次遍历这三部分,就是遍历了二叉树。
若以L、D、R分别表示遍历左子树、遍历根结点和遍历右子树,则有六种遍历方案:DLR、LDR、LRD、DRL、RDL、RLD。若规定先左后右,则只有前三种情况三种情况,分别是:
DLR——先(根)序遍历。
LDR——中(根)序遍历。
LRD——后(根)序遍历。
其中又以中序遍历算法最常用,递归定义是:
若二叉树为空,则遍历结束;否则
⑴ 中序遍历左子树(递归调用本算法);
⑵ 访问根结点;
⑶ 中序遍历右子树(递归调用本算法)。
遍历二叉树是按一定的规则将树中的结点排列成一个线性序列,即是对非线性结构的线性化操作。如何找到遍历过程中动态得到的每个结点的直接前驱和直接后
继(第一个和最后一个除外)?如何保存这些信息?
设一棵二叉树有n个结点,则有n-1条边(指针连线) ,而n个结点共有2n个指针域(Lchild和Rchild) ,显然有n+1个空闲指针域未用。则可以利用这些空闲的指针域来存放结点的直接前驱和直接后继信息。对结点的指针域做如下规定:
若结点有左孩子,则Lchild指向其左孩子,否则,指向其直接前驱;
若结点有右孩子,则Rchild指向其右孩子,否则,指向其直接后继;
为避免混淆,对结点结构加以改进,增加两个标志域,即
Lchild Ltag data Rchild Rtag
线索二叉树的结点结构
LTag取值:
0:Lchild域指示结点的左孩子
1:Lchild域指示结点的前驱
RTag取值:
0:Rchild域指示结点的右孩子
1:Rchild域指示结点的后继
用这种结点结构构成的二叉树的存储结构;叫做线索链表;指向结点前驱和后继的指针叫做线索;按照某种次序遍历,加上线索的二叉树称之为线索二叉树。
二叉树的线索化指的是依照某种遍历次序使二叉树成为线索二叉树的过程。线索化的过程就是在遍历过程中修改空指针使其指向直接前驱或直接后继的过程。
仿照线性表的存储结构,在二叉树的线索链表上也
添加一个头结点head,头结点的指针域的安排是:
◆Lchild域:指向二叉树的根结点;
◆Rchild域:指向中序遍历时的最后一个结点;
◆二叉树中序序列中的第一个结点Lchild指针域和最后一个结点Rchild指针域均指向头结点head。
线索二叉树中,由于有线索存在,在某些情况下可以方便地找到指定结点在某种遍历序列中的直接前驱或直接后继。此外,在线索二叉树上进行某种遍历比在一般的二叉树上进行这种遍历要容易得多,不需要设置堆栈,且算法十分简洁,时间复杂度最多为O(n)。
二叉查找树,它或者是一棵空树,或者是具有下列性质二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉查找树。
其查找过程和次优二叉树类似,通常采取二叉链表存储,若中序遍历,可得到一个有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。每次插入的新的结点都是二叉排序树上新的叶节点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索,插入,删除的复杂度等于树高,为O(log(n)).
二叉树节点类
template class BinTreeNode{
friend class BinTree;
public:
BinTreeNode(){
LChild(NULL);
RChild(NULL);
}
BinTreeNode(T &value){
data = value;
LChild = RChild = NULL;
}
BinTreeNode(T &value, BinTreeNode *left = NULL, BinTreeNode *right = NULL){
data = value;
LChild = left;
RChild = right;
}
BinTreeNode *copy()const{
BinTreeNode *newLeft, *newRight, *newptr;
if (LChild != NULL){
newLeft = LChild->copy();
}
else{
newLeft = NULL;
}
if (RChild != NULL){
newRight = RChild->copy();
}
else{
newRight = NULL;
}
newptr = new BinTreeNode (data, newLeft, newRight);
return newptr;
}
void release(){
if (LChild != NULL){
LChild->release();
delete LChild;
LChild = NULL;
}
if (RChild != NULL){
RChild->release();
delete RChild;
RChild = NULL;
}
}
T GetData()const{
return data;
}
BinTreeNode *GetLeft()const{
return LChild;
}
BinTreeNode *GetRight()const{
return RChild;
}
void SetData(T &value){
data = value;
}
void SetLeft(BinTreeNode *L){
LChild->release();
delete LChild;
LChild = L;
}
void SetRight(BinTreeNode *R){
RChild->release();
delete RChild;
RChild = R;
}
private:
T data;
BinTreeNode *LChild;
BinTreeNode *RChild;
};
template class BinTree{
protected:
BinTreeNode *root;
public:
BinTree(){
root = NULL;
}
BinTree(const BinTree &source){
root = source.root->copy();
}
BinTree(const T &value, BinTreeNode *left, BinTreeNode *right){
root = new BinTreeNode(value, left, right);
}
BinTreeNode *GetRoot()const{
BinTreeNode *current = Find(value);
if (current != NULL){
root = current = new BinTreeNode(value);
return root;
}
else{
return NULL;
}
}
BinTreeNode *Find(const T &value){
if (root->data == value){
return root;
}
else{
return nullptr;
}
}
void SetEmpty(){
root->release();
delete root;
root = NULL;
}
int IsEmpty(){
return root == NULL;
}
friend istream & operator >>(istream &in, BinTree &t){
T item[20], num;
cout << "input the num ";
in >> num;
cout << "input data ";
for (int i = 0; i < num; i++){
in >> item[i];
t.Insert(item[i]);
}
return in;
}
friend ostream & operator << (ostream &out, BinTree &t){
cout << "result ";
t.InOrder();
return out;
}
BinTreeNode *Find(BinTreeNode *t, T &value){
if (t == NULL || t->GetData() == value){
return t;
}
else{
if (value < t->GetData()){
return(Find(t->LChild, value));
}
else{
return(Find(t->RChild, value));
}
}
}
BinTreeNode *Find(T &value){
if (root == NULL){
return NULL;
}
else{
return Find(root, value);
}
}
int Insert(BinTreeNode *t, T &value){
if (t == NULL){
t = new BinTreeNode(value,NULL,NULL);
return 1;
}
if (value < t->GetData()){
Insert(t->GetLeft(), value);
}
else{
if (value > t->GetData()){
Insert(t->GetRight(), value);
}
else{
return 0;
}
}
}
int Insert(T &value){
if (root == NULL){
root = new BinTreeNode(value,NULL,NULL);
return 1;
}
else{
return Insert(root, value);
}
}
int Delete(BinTreeNode *t, T &value){
BinTreeNode *s;
if (t != NULL){
if (value < t->GetData()){
Delete(t->GetLeft, value);
}
else{
if (value > t->GetData()){
Delete(t->GetRight, value);
}
else{
if (t->GetLeft() != NULL&&t->GetRight() != NULL){
BinTreeNode *p = t->GetRight();
while (p->GetLeft() != NULL){
p = p->GetRight();
}
s = p;
t->SetData = s->SetData;
Delete(t->GetRight(), t->data);
return 1;
}
else{
s = t;
if (t->GetLeft() = NULL){
t = t->GetRight();
}
else{
if (t->GetRight() = NULL){
t = t->GetLeft();
}
}
delete s;
return 1;
}
return 0;
}
}
}
}
int Delete(T &value){
if (t = NULL){
return 0;
}
else{
return(Delete(root, value));
}
}
void InOrder(){
InOrder(root);
}
void InOrder(BinTreeNode *current){
if (current != NULL){
InOrder(current->LChild);
cout << current->data <<" ";
InOrder(current->RChild);
}
}
~BinTree(){
root->release();
delete root;
root = NULL;
}
};
void main(){
BinTree t;
cin >> t;
cout << t ;
cout << endl;
cout << "input another one" << endl;
cin >> x;
t.Insert(x);
cout << t;
cout << "delete one" << endl;
cin >> y;
t.Delete(y);
cout << t;
system("pause");
}
例子:一株二叉树
结果:
二叉查找树结果: