二叉树 的 存储与基本操作实现

数据结构课程学了二叉树,觉得自己大概理解了,但是实现还是总有困难,尤其是结构体指针这块,吃了不少亏

(一)存储与遍历(递归)

#include
#include 
#include
#include 
#include
using namespace std;

typedef struct BiTNode{			//定义结构体,包含数据域、左右子节点指针 
	int data;
	BiTNode *lchild,*rchild;
}BiTNode,*BiTree;				//定义一个BiTNode类型的结构体变量与结构体指针 

//建立二叉树 
void createBiTree(BiTree* t){	//此处必须为指针类型 
	int ch;
	scanf("%d",&ch);
	if(ch==-1){								//节点值输入为"-1"时,表示该节点没有左(右)叶节点 
		*t=NULL;
	}
	else{
		*t=(BiTree)malloc(sizeof(BiTNode));		//开辟一块BiTree指针类型的空间 
		(*t)->data=ch;
		printf("请输入%d的左子节点值:",ch);
		createBiTree(&(*t)->lchild);		//对地址进行操作,注意此格式 
		printf("请输入%d的右子节点值:",ch);
		createBiTree(&(*t)->rchild);
	}
}

//先序遍历(递归实现) 
void PreOrderTraverse(BiTree t){
	if(t==NULL)
		return;
	else{
		printf("%d",t->data);
		PreOrderTraverse(t->lchild);
		PreOrderTraverse(t->rchild);
	}
}

//中序遍历(递归实现)
void InOrderTraverse(BiTree t){
	if(t==NULL)
		return;
	else{
		InOrderTraverse(t->lchild);
		printf("%d",t->data);
		InOrderTraverse(t->rchild);
	}	
} 

//后序遍历(非递归) 
void PostOrderTraverse(BiTree t){
	if(t==NULL)
		return;
	else{
		PostOrderTraverse(t->lchild);
		PostOrderTraverse(t->rchild);
		printf("%d",t->data);
	}	
} 

 
//求树深度
int deepth(BiTree t){
	int deep=0;
	int ldeepth,rdeepth;
	if(t){
		ldeepth=deepth(t->lchild);
		rdeepth=deepth(t->rchild);
		deep=ldeepth>=rdeepth?ldeepth+1:rdeepth+1;
	}
	return deep;
} 

//交换左右子树(递归实现)
void swapt(BiTree t){
	BiTree temp;
	if(t==NULL)
		return;
	else{
		temp=t->lchild;
		t->lchild=t->rchild;
		t->rchild=temp;
		swapt(t->lchild);
		swapt(t->rchild);
	}
	return;
} 
 
int main(){
	BiTree t;
	BiTree *p=(BiTree*)malloc(sizeof(BiTNode));
	printf("请输入根节点的值:");
	createBiTree(&t);
	printf("先序遍历该二叉树为:\n");
	PreOrderTraverse(t);
	printf("\n");
	printf("中序遍历输出为:\n");
	InOrderTraverse(t);
	printf("\n");
	printf("后序遍历输出为:\n");
	PostOrderTraverse(t);
	printf("\n");	
	printf("树的深度为:%d\n",deepth(t));
	printf("先序遍历输出交换左右子树后的二叉树:\n");
	swapt(t);
	PreOrderTraverse(t); 
	printf("\n");

	return 0;
}

运行结果如下


二叉树 的 存储与基本操作实现_第1张图片


(二)遍历、交换左右子树非递归实现

从难度上,中序遍历的非递归是最简单的,前序遍历居中,后序遍历最难

前序遍历

//先序遍历(非递归) 
void PreOrderTraverse(BiTree root){
	if(root==NULL)
		return;
	BiTree p=root;
	stack s;
	while(!s.empty()||p){
		//遍打印边遍历,并存入栈中,以后需要借助这些根节点进入右子树 
		while(p){
			printf("%d ",p->data);
			s.push(p);
			p=p->lchild;
		}
		//当p为非空时,说明根和左子树都遍历完了,该进入右子树了 
		if(!s.empty()){
			p=s.top();
			s.pop();
			p=p->rchild;
		}
	}
}


中序遍历

//中序遍历
void InOrderTraverse(BiTree root)
{
	//空树
	if(root==NULL)
		return;
	//树非空
	BiTree p=root;
	stack s;
	while (!s.empty()||p){
		//一直遍历到左子树最下边,边遍历边保存根节点到栈中
		while(p){
			s.push(p);
			p = p->lchild;
		}
		//当p为空时,说明已经到达左子树最下边,这时需要出栈了
		if (!s.empty()){
			p = s.top();
			s.pop();
			printf("%d ",p->data);
			//进入右子树,开始新的一轮左子树遍历(这是递归的自我实现)
			p=p->rchild;
		}
	}
}


后序遍历

//后序遍历非递归
void PostOrderTraverse(BiTree root){
	if(root==NULL)
		return;
	stack s;
	//pCur:当前访问节点,pLastVisit:上次访问节点
	BiTree pCur,pLastVisit;
	pCur=root;
	pLastVisit =NULL;
	//先把pCur移动到左子树的最下边
	while(pCur){
		s.push(pCur);
		pCur=pCur->lchild;
	} 
	while(!s.empty()){
		//走到这里,pCur都是空,并已经遍历到左子树底端(看成扩充二叉树,则空,也是某科数的左孩子) 
		pCur=s.top();
		s.pop();
		//一个根节点被访问的前提是:无右子树或右子树已被访问过
		if(pCur->rchild==NULL||pCur->rchild==pLastVisit){
			printf("%d ",pCur->data);
			//修改最近被访问的节点
			pLastVisit=pCur; 
		} 
		//
		else{
			//根节点再次入栈 
			s.push(pCur);
			//进入右子树,且可以肯定右子树一定不为空
			pCur=pCur->rchild;
			while(pCur){
				s.push(pCur);
				pCur=pCur->lchild;
			} 
		} 
	}
	printf("\n");
} 

完整测试代码如下:


#include
#include
#include 
#include
#include
using namespace std;

typedef struct BiTNode{			//定义结构体,包含数据域、左右子节点指针 
	int data;
	BiTNode *lchild,*rchild;
}BiTNode,*BiTree;				//定义一个BiTNode类型的结构体变量与结构体指针 

//建立二叉树 
void createBiTree(BiTree* t){	//此处必须为指针类型 
	int ch;
	scanf("%d",&ch);
	if(ch==-1){								//节点值输入为"-1"时,表示该节点没有左(右)叶节点 
		*t=NULL;
	}
	else{
		*t=(BiTree)malloc(sizeof(BiTNode));		//开辟一块BiTree指针类型的空间 
		(*t)->data=ch;
		printf("请输入%d的左子节点值:",ch);
		createBiTree(&(*t)->lchild);		//对地址进行操作,注意此格式 
		printf("请输入%d的右子节点值:",ch);
		createBiTree(&(*t)->rchild);
	}
}

//先序遍历(非递归) 
void PreOrderTraverse(BiTree root){
	if(root==NULL)
		return;
	BiTree p=root;
	stack s;
	while(!s.empty()||p){
		//遍打印边遍历,并存入栈中,以后需要借助这些根节点进入右子树 
		while(p){
			printf("%d ",p->data);
			s.push(p);
			p=p->lchild;
		}
		//当p为非空时,说明根和左子树都遍历完了,该进入右子树了 
		if(!s.empty()){
			p=s.top();
			s.pop();
			p=p->rchild;
		}
	}
}

//中序遍历
void InOrderTraverse(BiTree root)
{
	//空树
	if(root==NULL)
		return;
	//树非空
	BiTree p=root;
	stack s;
	while (!s.empty()||p){
		//一直遍历到左子树最下边,边遍历边保存根节点到栈中
		while(p){
			s.push(p);
			p = p->lchild;
		}
		//当p为空时,说明已经到达左子树最下边,这时需要出栈了
		if (!s.empty()){
			p = s.top();
			s.pop();
			printf("%d ",p->data);
			//进入右子树,开始新的一轮左子树遍历(这是递归的自我实现)
			p=p->rchild;
		}
	}
}

//后序遍历非递归
void PostOrderTraverse(BiTree root){
	if(root==NULL)
		return;
	stack s;
	//pCur:当前访问节点,pLastVisit:上次访问节点
	BiTree pCur,pLastVisit;
	pCur=root;
	pLastVisit =NULL;
	//先把pCur移动到左子树的最下边
	while(pCur){
		s.push(pCur);
		pCur=pCur->lchild;
	} 
	while(!s.empty()){
		//走到这里,pCur都是空,并已经遍历到左子树底端(看成扩充二叉树,则空,也是某科数的左孩子) 
		pCur=s.top();
		s.pop();
		//一个根节点被访问的前提是:无右子树或右子树已被访问过
		if(pCur->rchild==NULL||pCur->rchild==pLastVisit){
			printf("%d ",pCur->data);
			//修改最近被访问的节点
			pLastVisit=pCur; 
		} 
		//
		else{
			//根节点再次入栈 
			s.push(pCur);
			//进入右子树,且可以肯定右子树一定不为空
			pCur=pCur->rchild;
			while(pCur){
				s.push(pCur);
				pCur=pCur->lchild;
			} 
		} 
	}
	printf("\n");
} 
 
int main(){
//	freopen("input11.txt","r",stdin);
	BiTree t;
	BiTree *p=(BiTree*)malloc(sizeof(BiTNode));
	printf("请输入根节点的值:");
	createBiTree(&t);
	printf("\n");
	printf("先序遍历该二叉树为:\n");
	PreOrderTraverse(t);
	printf("\n");
	printf("中序遍历输出为:\n");
	InOrderTraverse(t);
	printf("\n");
	printf("后序遍历输出为:\n");
	PostOrderTraverse(t);
	return 0;
}

交换左右子树:

void Exchange(BiTree bt){
	queue q;
	BiTree p;
    if(bt!=NULL){
        q.push(bt);
    }
    while(!q.empty()){
        BiTree p=q.front();
        q.pop();		//出队
        if(p->lchild!=NULL){
            q.push(p->lchild);
        }
        if(p->rchild!=NULL){
            q.push(p->rchild);
        }
        BiTree temp;
        temp=p->lchild;
        p->lchild=p->rchild;
        p->rchild=temp;
    }
    return;
}




执行效果图:

二叉树 的 存储与基本操作实现_第2张图片






你可能感兴趣的:(ACM,树,堆)