目录
输入示例:
依次输入: AB.D..CE.F...来先序创建二叉树
1结构体:
typedef struct tree{
char data;
struct tree *leftc,*rightc;
}tree;
2创建二叉树
void create_tree(tree *&x){
char ch;
ch=getchar();
if(ch=='#'){
x=NULL;
}else{
x=new tree;
x->data=ch;
create_tree(x->leftc);
create_tree(x->rightc);
}
}
关于*、&之间的浅显认识:
3遍历二叉树
3.1先序遍历:
//先序遍历 (递归)
void print(tree *t){
if(t==NULL)
return;
else{
cout<<t->data<<"->";
print(t->leftc);
print(t->rightc);
}
}
//非递归
void print2(tree *n){
tree *stack[100];
int top=0;
tree *p=n;
if(n==NULL)
return;
else{
while(p!=NULL||top!=0){
if(p!=NULL){
stack[++top]=p;
cout<<p->data<<"->";
p=p->leftc;
}else{
p=stack[top--];
p=p->rightc;
}
}
}
}
3.2中序遍历
//中序遍历
void middle_print(tree *t){
if(t==NULL)
return;
else{
middle_print(t->leftc);
cout<<t->data<<"->";
middle_print(t->rightc);
}
}
//中序遍历非递归
void middle_print2(tree *t){
tree *stack[50];
int top=0,flag=1;
tree *p=t;
if(p==NULL){
return;
}else{
do{
while(p!=NULL){
stack[++top]=p;
p=p->leftc;
}
if(top==0) flag=0;
else{
p=stack[top];top--;
cout<<p->data<<"->";
p=p->rightc;
}
}while(flag!=0);
}
}
3.3后序遍历
此处步骤只有一部分,请自己思考动手,在草稿纸上进行步骤的演变。
后序遍历
1.创建s1指针数组,用来存取节点。s2用来标记是否访问(0:未访问、1:访问,为什么要标记呢?为了在左右孩子出栈后方便父结点也出栈)
2.先do while()循环使其根节点以及左孩子节点入s1数组(栈),同时s2数组标记为0
0 1 2 3 4 A B D
0 1 2 3 4 0 0->1 0 2.if else 语句判断,条件正确的进入,s2[top]==0(此节点未访问)条件正确进入,进入s1[top]的右孩子节点,将此节点赋值给p,使得s1[top]=1,标记为访问(刷新s2表)。
3.继续do while()循环,使得s1[top]的右孩子入栈。
4.继续2的步骤判断分别进入语句中操作。
//后序遍历非递归
void back_print2(tree *t){
tree *s1[100];
int flag=1,s2[100],top=0;
tree *p=t;
if(p==NULL)
return;
else{
do{
while(p!=NULL){
s1[++top]=p;s2[top]=0;p=p->leftc;
}
if(top==0) flag=0;
else if(s2[top]==0){
p=s1[top]->rightc;s2[top]=1;
}else{
p=s1[top];top--;
cout<<p->data<<"->";
p=NULL;//防止死循环
}
}while(flag!=0);
}
}
3.4层次遍历
思想:
1.根节点A入队
2.A出队,在出队的同时,孩子节点B、C入队
3.队头节点B出队,出队的同时孩子节点D入队。
4..队头节点C出队,同时其孩子节点E入队。
5.以此循环到节点为空,结束循环。
//层次遍历
void cengci(tree *t){
if(t==NULL)
return;
queue<tree *>que;//创建一个树节点指针的队列
que.push(t);
while(!que.empty()){
tree *p=que.front();
cout<<p->data<<"->";
que.pop();
if(p->leftc!=NULL){
que.push(p->leftc);
}
if(p->rightc!=NULL){
que.push(p->rightc);
}
}
}
4.深度优先搜遍历
A 是第一个访问的,然后顺序是 B、D,然后是 E。接着再是 C、F、G。
那么,怎么样才能来保证这个访问的顺序呢?
分析一下,在遍历了根结点后,就开始遍历左子树,最后才是右子树。
因此可以借助堆栈的数据结构,由于堆栈是后进先出的顺序,由此可以先将右子树压栈,然后再对左子树压栈,
这样一来,左子树结点就存在了栈顶上,因此某结点的左子树能在它的右子树遍历之前被遍历。
深度优先搜索遍历是与栈结合:
1.根节点入栈
2.进入while循环
3.然后将栈顶元素赋值给q,根节点(栈顶节点)输出,再出栈
4.继续判断左右子节点是否为空:不空—入栈、为空—继续while循环(步骤2)。
5.直到栈为空。
//深度优先搜索
void def(tree *t){
stack<tree *>p;
p.push(t);
tree *q;
while(!p.empty()){
q=p.top();
cout<<q->data<<"->";
p.pop();
if(q->rightc!=NULL){
p.push(q->rightc);
}
if(q->leftc!=NULL){
p.push(q->leftc);
}
}
}
5.广度优先搜索遍历
广度遍历又可称为宽度遍历:在一定程度上也是层次遍历。
如图遍历顺序为a,b,c,d,e,f
1.首先根节点入队
2.进入while循环
3.将队首元素赋值给p,出栈输出p->data,根节点出队,然后进行判断左右孩子节点是否为空:不空—孩子入队、空—继续while循环(步骤2)。
4.直到队列为空。
void bfs(tree *t)
{
queue<tree *>q;
q.push(t);
tree *p;
while(!q.empty()){
p=q.front();
q.pop();
cout<<p->data<<"->";
if(p->rightc!=NULL){
q.push(p->rightc);
}
if(p->leftc!=NULL){
q.push(p->leftc);
}
}
}