二叉树的逻辑结构
1>二叉树只有两个分支,左子树和右子树
2>斜树
3>满二叉树:每一个分支节点都有一个左子树和右子树,而且所有叶子都在同一层上,叶子只能出现在最下面一层;只有度为0和度为2的结点
4> 完全二叉树:满二叉树去掉一些连续的结点就变成了完全二叉树,就是总最后一层开始删除,而且是从右到左去删除的才能称之为完全二叉树
二叉树的基本性质:
1>第i层上最多只有2的i-1次方的结点
2>深度为k的二叉树中,最多有2的k次方-1个结点,最少有k个结点
3>树中的结点数=叶子结点数(叶子的个数)+度为2的结点的个数【几个式子推出来的】
4>完全二叉树的深度为
5> 结点i的
双亲结点为i/2
左孩子结点为2i 右孩子结点为2i+1
二叉树的存储结构:
结构体
struct biNode
{
char data;
biNode *lchild,*rchild;
}
二叉树的遍历
1>前序 【先访问左子树,然后再是右子树】很明显的递归味
void Bitree::preorder(Binode *bt)
{if(bt==NULL)
return ;
else
{
visit(bt->data);
preorder(bt->lchild);
preorder(bt->rchild);
}
}
2>中序【根节点在中间被遍历】使用 2 1 3 的方法去套每一个字母,前后都可以使用这种方法struct Bitree::inorder(binode *bt)
{
if(bt==NULL)
return ;
else{
inorder(bt->lchild);
visit(bt->data);
inorder(bt->rchild);
}}
3>后序
struct Bitree::postorder(binode *bt)
{
if(bt==NULL)
return ;
else
{
visit(bt->data);
postorder(bt->lchild);
postorder(bt->rchild);
}}
4>层序
#include<queue>
struct Bitree::leverorder()
{
if(root==NULL)//二叉树为空
return ;
else
{
queue.enQueue(root);
while(!queue.isempty())
{
q=queue.deQueue();
visit(q->data);
if(q->lchild)!=NULL)
queue.enqueue(q->lchild);
if(q->rchild!=NULL)
queue.enqueue(q->rchild);
}}
}
二叉树的创建:
前序创建:
BiTree::BiTree()
{
root = creat(root);//调函数构建二叉树
}
Bitree* BItree::creat(binode *bt)
{
input(ch);
if(ch=='#')
{
bt=NULL;
}
else
{
bt=new binode;
bt->data=ch;
bt->lchild=creat(bt->lchild);
bt->rchild=creat(bt->rchild);
}
return bt;
}
第二种:
BiTree::BiTree()
{
Creat(root);
}
void BItree::creat(binode * &bt)
{
input(ch);
if(ch=='#')
{
bt=NULL;
}
else
{
bt=new BiNode;
bt->data=ch;
Creat(bt->lchild);
Creat(bt->rchild);
}
return ;
}
这两种方法最大的区别就是括号中传入的指针加了一个应用符号&
原因是:
在C++中,使用引用符号
&
是为了能够修改指针变量本身,而不仅仅是修改指针所指向的内容。这是因为在C++中,函数参数的传递默认是按值传递的,即使对于指针类型,传递给函数的也是指针的值(即地址),而不是指针本身。如果在函数内部修改了指针的值(即让它指向另一个地址),这种修改不会影响到函数外部的原始指针。为了让函数能够修改外部的指针变量,需要传递指针的引用。
二叉树的删除函数
void BiTree::release(BiNode *bt)
{
if(bt->lchild!=NULL)
{
release(bt->lchild);
}
if(bt->rchild!=NULL)
{
release(bt->rchild);
}
// if(bt->rchild==NULL&&bt->lchild==NULL)
// {
cout<<"delete "<<bt->data<<endl;
delete bt;
// }
}
那三条//函数,如果把//去掉的话(也就是不注释),那么最后两个数据删不掉
可以用一个例子来解释最后一句话:
二叉树的扩展前序序列
AB##C##
传入A之后,经过两个判断语句后进入了删除左指针和右指针的递归函数,进行完这两个递归函数后B,C位置的指针就变成了野指针,这个时候再来进行if(bt->rchild==NULL&&bt->lchild==NULL)判断的话,就会出错【root->lchild为野指针,他的值不是空]
总共的二叉树函数
/**字符串建树 并实现遍历(待填充代码)*/
#include<iostream>
#include<stdio.h>
#include<queue>
using namespace std;
struct BiNode
{
char data;//数据域
BiNode *lchild, *rchild;//左右儿子指针
};
class BiTree {
private:
BiNode *root; //指向根结点的头指针
public:
BiTree()
{
root = creat(root);//调函数构建二叉树
}
~BiTree()
{
// release(root);
}
BiNode * getRoot(){return root;}
BiNode *creat(BiNode *bt); //构造函数调用
void release(BiNode *bt); //析构函数调用,释放树的存储空间
void preOrder(BiNode *bt); //前序遍历函数调用
void inOrder(BiNode *bt); //中序遍历函数调用
void postOrder(BiNode *bt);//后序遍历函数调用
void leverOrder(BiNode *bt);//后序遍历函数调用
};
/**前序构建二叉树*/
BiNode* BiTree::creat(BiNode *bt)
{
char ch;
cin>>ch;
if(ch=='#')
{
bt=NULL;
}
else
{
bt=new BiNode;
bt->data=ch;
bt->lchild=creat(bt->lchild);
bt->rchild=creat(bt->rchild);
}
return bt;
}
void BiTree::release(BiNode *bt)
{
if(bt->lchild!=NULL)
{
release(bt->lchild);
}
if(bt->rchild!=NULL)
{
release(bt->rchild);
}
cout<<"delete "<<bt->data<<endl;
delete bt;
}
/**前序遍历*/
void visit(char ch)
{
cout<<ch;
}
void BiTree::preOrder(BiNode * bt)
{
if(bt==NULL)
{
return ;
}
else
{
visit(bt->data);
preOrder(bt->lchild);
preOrder(bt->rchild);
}
}
void BiTree::inOrder(BiNode *bt)
{
if(bt==NULL)
{
return ;
}
else
{
inOrder(bt->lchild);
visit(bt->data);
inOrder(bt->rchild);
}
}
void BiTree::postOrder(BiNode *bt)
{
if(bt==NULL)
{
return ;
}
else
{
postOrder(bt->lchild);
postOrder(bt->rchild);
visit(bt->data);
}
}
void BiTree::leverOrder(BiNode *root)
{
if(root==NULL)//二叉树为空
return ;
else
{
/*那么我们来思考一下,这里为什么不能是
queue<BiNode> h;//创建一个队列 类型
h.push(*root);这个样子写的话,漏洞百出
*/
queue<BiNode*> h;//创建一个队列 类型
h.push(root);//将根指针放进去
while(!h.empty())
{
BiNode* q=h.front();
h.pop();
visit(q->data);
if(q->lchild!=NULL)
h.push(q->lchild);
if(q->rchild!=NULL)
h.push(q->rchild);
}
}
}
int main()
{
BiTree tree;
// cout << "\n前序遍历二叉树"<<endl;
// tree.preOrder(tree.getRoot());
//
//
// cout << "\n中序遍历二叉树"<<endl;
// tree.inOrder(tree.getRoot());
// cout<<endl;
//
//
// cout << "\n后序遍历二叉树"<<endl;
// tree.postOrder(tree.getRoot());
//
//
// cout << "\n层序遍历二叉树"<<endl;
tree.leverOrder(tree.getRoot());
// cout<<"\n删除的结果为:"<<endl;
return 0;
}