数据结构-链式二叉树

版权声明:转载请注明出处。 https://blog.csdn.net/baidu_38304645/article/details/82964439

树形结构是一类重要的非线性数据结构。其中以树和二叉树最为常用。直观看来,树是以分支关系定义的层次结构。

树是n个结点的有限集,在任意一颗非空树中,有且仅有一个特定称为根的结点,当n>1时,其余结点可分为m个互不相交的有限集

T1,T2,..Tm,其中每一个集合本身又是一颗树,并且称为根的子树。

二叉树是度不大于2的有序树(每个结点最多两颗子树,子树有左右之分)。

下面给出

首先是辅助宏的定义:

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
#define UNDERFLOW -2
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define NULL 0
typedef int Status;
typedef char TElemType;

二叉树的存储结构定义:

//二叉树的二叉链式存储结构定义
typedef struct BiTNode{
   TElemType data;
   struct BiTNode *lchild,*rchild; //左孩子结点 右孩子结点
}BiTNode,*BiTree; 

先序创造二叉树各节点 注意输入时空指针不要丢 输入空格是空树,停止 否则创造根节点 递归创造左子树 递归创造右子树.

Status CreatBiTree(BiTree &T){
	/*先序创造二叉树各节点 注意输入时空指针不要丢
	输入空格是空树,停止 否则创造根节点 递归创造左子树
	递归创造右子树*/
   TElemType e;
   scanf("%c",&e);
   if(e==' ')
	   T=NULL;
   else{
       T=(BiTree)malloc(sizeof(BiTNode));
       if(!T)//存储分配失败
           exit(OVERFLOW);
	   T->data=e;
	   T->lchild=NULL;
	   T->rchild=NULL;
	   CreatBiTree(T->lchild);
	   CreatBiTree(T->rchild);
   }
   return OK;
}

销毁以T为结点的二叉树 注意他的子孙结点也要释放 树为空什么都不做 否则递归释放左子树 递归释放右子树  释放根节点

Status DestroyBiTree(BiTree &T){
	/*销毁以T为结点的二叉树 注意他的子孙结点也要释放
	树为空什么都不做 否则递归释放左子树 递归释放右子树
    释放根节点*/
   if(T){
     DestroyBiTree(T->lchild);
     DestroyBiTree(T->rchild);
     free(T);
	 T=NULL;//不可丢
   }
   return OK;
}

输出e 输出二叉树 调用先序遍历函数 用函数传递给其参数visit即可.

Status PrintTElem(TElemType e){
	//输出e 输出二叉树 调用先序遍历函数 用函数传递给其参数visit即可
   printf("%c",e);
   return OK;
}

求二叉树的树深  如果T为空 d=0 否则递归求出左子树的树深 再递归求出右子树的树深  最后树的深度为两个树深最大值加一

int TreeDepth(BiTree T){
	/*求二叉树的树深
    如果T为空 d=0 否则递归求出左子树的树深 再递归求出右子树的树深 
	最后树的深度为两个树深最大值加一*/
   int d,d1,d2;
   if(!T)
      d=0; 
   else{
      d1=TreeDepth(T->lchild);
      d2=TreeDepth(T->rchild);
      d=d1>d2?d1+1:d2+1;
   }
    return d;
}

递归法求结点个数  如果树为空 结点数为0 否则结点数是 递归求得左子树的结点数加上递归求得右子树的结点数加一.

int NodeCount(BiTree T){
	/*递归法求结点个数 
	如果树为空 结点数为0
	否则结点数是 递归求得左子树的结点数加上递归求得右子树的结点数加一*/
   if(!T) 
       return 0;
   else
       return 1+NodeCount(T->lchild)+NodeCount(T->rchild);
}

递归法求叶子结点的个数 如果树为空叶子数为0  如果是只有一个根节点叶子数是1 否则先递归求左子树与右子树的叶子数 整个数结点数就是左右子树结点之和。

int LeafCount(BiTree T){
	/*递归法求叶子结点的个数
	如果树为空叶子数为0  如果是只有一个根节点叶子数是1
	否则先递归求左子树与右子树的叶子数 整个数结点数就是左右子树结点之和*/
   if(!T)
       return 0;
   if(!T->lchild&&!T->rchild)
	   return 1;
   else
	   return LeafCount(T->lchild)+LeafCount(T->rchild);
}

先序遍历二叉树.如果树不空 先访问根节点 在递归的先序遍历左子树 在递归的先序遍历右子树.

Status PreOrderTraverse(BiTree T,Status (*visit)(TElemType)){
   //先序遍历二叉树
   //如果树不空 先访问根节点 在递归的先序遍历左子树 在递归的先序遍历右子树
   if(T){
       if(visit(T->data))
          if(PreOrderTraverse(T->lchild,visit))
            if(PreOrderTraverse(T->rchild,visit))
               return OK; 
       return ERROR;//只要一次失败就返回ERROR
   }
   return OK;
}

中序遍历二叉树 如果树不空 先在递归的先序遍历左子树 再访问根节点  再递归的先序遍历右子树.

Status InOrderTraverse(BiTree T,Status (*visit)(TElemType)){
	//中序遍历二叉树
	//如果树不空 先在递归的先序遍历左子树 再访问根节点  再递归的先序遍历右子树
   if(T)  {
	   if(InOrderTraverse(T->lchild,visit))
           if(visit(T->data))
              if(InOrderTraverse(T->rchild,visit))
                  return OK;
       return ERROR;
   }   
   return OK;
}

后序遍历二叉树 如果树不空 先在递归的先序遍历左子树 再递归的先序遍历右子树 再访问根节点 .

Status PostOrderTraverse(BiTree T,Status(*visit)(TElemType)){
	//后序遍历二叉树
	//如果树不空 先在递归的先序遍历左子树 再递归的先序遍历右子树 再访问根节点  
	if(T){
		if(PostOrderTraverse(T->lchild,visit))
		   if(PostOrderTraverse(T->rchild,visit))
		    	if(visit(T->data))
		           return OK;	
	    return ERROR;			
	}
	return OK;
}

基于先序遍历求叶子结点数 count为计数器 初值0 函数返回值为叶子结点数.实际将先序遍历中的visit函数换成判断当前结点是否是叶子结点 是就加一的操作即可.

int PreOrder_LeafCount(BiTree T,int &count){
	//基于先序遍历求叶子结点数 count为计数器 初值0 函数返回值为叶子结点数 
	//实际将先序遍历中的visit函数换成判断当前结点是否是叶子结点 是就加一的操作即可
   if(T){
        if(!T->lchild&&!T->rchild)
             count++;
        else{
		     PreOrder_LeafCount(T->lchild,count);
	         PreOrder_LeafCount(T->rchild,count);
		}
   }
   return count;
}

复制T树给X T不变, 如果树空X赋值BULL.

Status CopyBiTree(BiTree T,BiTree &X){
	//复制T树给X T不变
	//如果树空X赋值BULL 
   if(!T)
       X=NULL;
   else{//否则 创造结点 在递归复制左子树和右子树
	   X=(BiTree)malloc(sizeof(BiTNode));
	   if(!X)//存储分配失败
		   exit(OVERFLOW);
       X->data=T->data;
	   X->lchild=NULL;
	   X->rchild=NULL;
       CopyBiTree(T->lchild,X->lchild);
       CopyBiTree(T->rchild,X->rchild);
   }
   return OK;
}

将树各节点的左右孩子互换.

Status ExchangeBiTree(BiTree &T){
	//将树各节点的左右孩子互换
	BiTNode * temp;
    if(T){//如果树存在 交换左右孩子
	    temp=T->lchild;
	    T->lchild=T->rchild;
	    T->rchild=temp;
	    ExchangeBiTree(T->lchild);//递归左子树 互换左右孩子
		ExchangeBiTree(T->rchild);//递归右子树 互换左右孩子
	}
    return OK;
}

从树中查找第一个结点等于x的结点 若找到则返回TRUE 并用p带回该节点的地址 若找不到函数返回FALSE p赋值为NULL.

Status LocateNode(BiTree T,TElemType x,BiTree &p){
	//从树中查找第一个结点等于x的结点 若找到则返回TRUE 并用p带回该节点的地址
	//若找不到函数返回FALSE p赋值为NULL
	if(!T){
	   p=NULL;
	   return FALSE;
	}
    else if(T->data==x){
	   p=T;
	   return TRUE;
	}
	else{
		//递归左右子树
	   if(LocateNode(T->lchild,x,p))
		    return TRUE;
	   else if(LocateNode(T->rchild,x,p))
		    return TRUE;
	   else{
			p=NULL;
		    return FALSE;
	   }
	}
}

已知树T中某结点值等于x 定位到该节点的双亲结点 若双亲结点存在 即不是根节点 则parent_p返回双亲结点的地址 LR=0 是双亲的左孩子 LR=1是双亲的右孩子 返回TRUE   否则parent_p=NULL 返回FALSE.

Status LocateParent(BiTree T,TElemType x,BiTree &parent_p,int &LR){
	/*已知树T中某结点值等于x 定位到该节点的双亲结点 若双亲结点存在 即不是根节点
	则parent_p返回双亲结点的地址 LR=0 是双亲的左孩子 LR=1是双亲的右孩子 返回TRUE  
	否则parent_p=NULL 返回FALSE*/
    if(T->data==x){
	   parent_p=NULL;
	   return FALSE;
	}
    else if(T->lchild&&T->lchild->data==x){ 
     	LR=0; 
     	parent_p=T;
    	return TRUE;
	}
    else if(T->rchild&&T->rchild->data==x){ 
     	LR=1; 
     	parent_p=T;
    	return TRUE;
	}
    else{
		//递归左右子树
	   if(T->lchild&&LocateParent(T->lchild,x,parent_p,LR))
	      return TRUE;
	   else if(T->rchild&&LocateParent(T->rchild,x,parent_p,LR))
		  return TRUE;
	   else{
		  parent_p=NULL;
		  return FALSE;
	   }
	}
}

删除根结点值为x的子树 若存在x结点删除成功 返回OK 否则返回x不存在ERROR.

Status DeleteChild(BiTree &T,TElemType x){
	//删除根结点值为x的子树 若存在x结点删除成功 返回OK 否则返回x不存在ERROR
	BiTNode *p,*parent_p;
	int LR;
	if(LocateNode(T,x,p)){ //定位x 所在结点
		if(LocateParent(T,x,parent_p,LR)){//如果x有双亲结点 
		  if(!LR)  //是左孩子
		     DestroyBiTree(parent_p->lchild);
	      else if(LR==1)//是右孩子
             DestroyBiTree(parent_p->rchild);
	   }
	   else//x是根节点
	      DestroyBiTree(T);
	}	   
    else//x结点不存在
	   return ERROR;
}

非递归中序遍历方法1:  T入栈,重复如下操作至栈空:{ 只要栈顶元素不为空则[其左孩子入栈]。最后栈顶必为空,出栈。
 若下一个栈顶元素不空则出栈访问且右孩子入栈.

Status InOrderTraverse_NonRecur_1(BiTree T,Status (*visit)(TElemType)){
	/*非递归中序遍历方法1
	T入栈,重复如下操作至栈空:
	{ 只要栈顶元素不为空则[其左孩子入栈]。最后栈顶必为空,出栈。
	若下一个栈顶元素不空则出栈访问且右孩子入栈 */
   SqStack S;
   InitStack(S);
   BiTNode * p=T;
   while(p||!StackEmpty(S)){ 
      while(p){
	     Push(S,p);
	     p=p->lchild;
	  }
      Pop(S,p);
      visit(p->data);
	  p=p->rchild;
   }
   return OK;
}

非递归中序遍历方法2.何时递归 根节点不空将左孩子入栈做新根节点 何时不递归 根节点为空不递归 从后以前的空根节点出栈 访问下一个栈顶元素并将右孩子入栈  当栈中无元素时遍历完成.

Status InOrderTraverse_NonRecur_2(BiTree T,Status (*visit)(TElemType)){
	/*非递归中序遍历方法2
	何时递归 根节点不空将左孩子入栈做新根节点
	何时不递归 根节点为空不递归 从后以前的空根节点出栈 访问下一个栈顶元素并将右孩子入栈
	当栈中无元素时遍历完成*/
    SqStack S;
	InitStack(S);
	BiTNode *p;
	if(!T){
	    printf("空树");
		return ERROR;
	}
	else{ 
		Push(S,T);
	    while(!StackEmpty(S)){
	    //p的左孩子入栈 直到p为空指针 此循环后栈顶元素是NULL 相当于走到左子树外
		   while(GetTop(S,p)&&p)
		       Push(S,p->lchild);
		   Pop(S,p);//左子树是空树 对应的空指针出栈 下一步将访问根节点
		   if(!StackEmpty(S)){
			   //栈内有元素说明没有遍历完 下一步访问栈顶根结点 之后栈顶跟结点的右孩子入栈
		       Pop(S,p);
		       visit(p->data);
		       Push(S,p->rchild);
		   }
		}
		return OK;
	}
}

猜你喜欢

转载自blog.csdn.net/baidu_38304645/article/details/82964439