二叉树功能测试代码

 

//****算法复习*********
//****使用纯C编写****************
//******作者:王强******
//最后一次修改日期:2020年7月18日(持续更新)
#include<iostream>
using namespace std;
#define maxSize 50
typedef int ElemType;
typedef enum { Link, Thread }PointerTag;    //Link = 0表示指向左右孩子指针;Thread = 1表示指向前驱或后继的线索
//*************************************************************************************************************
typedef struct BiNode      //二叉树存储结构
{
	ElemType data;               //数据域
	struct BiNode* lchild;   //左孩子
	struct BiNode* rchild;  //右孩子
}BiNode;
typedef struct ThreadBiNode //线索二叉树存储结构
{
	ElemType data;
	struct ThreadBiNode* lchild;
	struct ThreadBiNode* rchild;
	int ltag;              //左线索标志
    int rtag;              //右线索标志
}ThreadBiNode;
//*************************************************************************************************************
BiNode* Createtree(ElemType a[], int n1, int m1, ElemType b[], int n2, int m2);//根据先序和中序遍历结果创建唯一确定的二叉树
ThreadBiNode* CreateTree(ElemType a[], int n1, int m1, ElemType b[], int n2, int m2);//根据先序和中序遍历结果创建唯一确定的二叉树
void pre_Noncirculate(BiNode* T);    //先序遍历二叉树的非递归算法
void Inorder_Noncirculate(BiNode* T);  //中序遍历二叉树的非递归算法
void  Post_Noncirculate(BiNode* T);//后序遍历二叉树的非递归算法
void  LevelOrder(BiNode* T);//二叉树层次遍历
void  LevelOrder2(ThreadBiNode* T);//线索二叉树层次遍历
int Tree_High(BiNode* T);  //求二叉树高度的非递归算法
int Tree_High2(BiNode* T);   //求二叉树高的递归算法
void Tree_levelSum(BiNode* T); //求二叉树每层的结点个数
int CountDoublesonNodes(BiNode* T);   //统计一棵二叉树中双分支结点的个数
BiNode* SwapTree(BiNode* T);    //交换左右子树
void Find_Pre(BiNode* T, int k); //找先序遍历序列中第k个结点的值
void DeleteTree(BiNode* T);    //删除一棵以T为根的二叉树
void FindThenDelete(BiNode* T, ElemType x); //在二叉树中查找所有结点值为x的结点,并删除以其为根的子树
int FindAncestorToChild(BiNode* T, ElemType X, BiNode* temp[]);//求根节点到某一结点的路径,temp为辅助栈,用来存放祖先结点,返回辅助栈的栈顶指针
void FindCommonAncestor(BiNode* T, ElemType x, ElemType y, BiNode* temp1[], BiNode* temp2[]);//查找两个结点的公共祖先
void InThread(ThreadBiNode* &T,ThreadBiNode *&pre);//对二叉树进行中序线索化
void CreateInThread(ThreadBiNode* T);//建立中序线索二叉树
ThreadBiNode* FirstNode(ThreadBiNode* T);//在中序线索二叉树中,查找中序序列下的第一个结点
ThreadBiNode* NextNode(ThreadBiNode* T);//在中序线索二叉树中,查找结点的中序后继结点
void ThreadInOrder(ThreadBiNode* T);   //在中序线索二叉树上使用线索执行二叉树中序遍历
ThreadBiNode* InPostPre(ThreadBiNode* T, ThreadBiNode* p);//在中序线索树上求指定结点在后序前驱结点
//*************************************************************************************************************
int main()
{
	ElemType pre[] = { 9,7,3,51,8,16,22,0,2,4 }, in[] = { 3,8,51,16,7,9,0,22,4,2 };//先序序列和中序序列
	ThreadBiNode* T = CreateTree(pre, 0, 9, in, 0, 9);
	//BiNode* temp1[maxSize], * temp2[maxSize];
	//Inorder_Noncirculate(T);
	//Post_Noncirculate(T);		
	/*BiNode* stacka[maxSize];     //定义辅助栈stacka并初始化
	int topa=FindAncestorToChild(T, 8,stacka);
	while (topa!=-1)  //访问辅助栈中的结点
	{
		printf("%d%s", stacka[topa--]->data,"       ");
	}*/
	//FindCommonAncestor(T, 51, 22, temp1, temp2);
	//printf("%d\n", T->rchild->lchild->ltag);
	//LevelOrder2(T);
	CreateInThread(T);
	//printf("%d\n", T->rchild->lchild->ltag);
	//T = T->rchild->rchild->lchild->lchild;
	//printf("%d\n", T->rchild->lchild->lchild->ltag);
	//printf("%d\n",FirstNode(T)->data);
	//ThreadInOrder(T);
	ThreadBiNode* temp = T->rchild;
	//InPostPre(T, temp);
	//printf("%d\n", T->rtag);
	printf("%d\n", InPostPre(T, temp)->data);
	//printf("%s%d", "树高:",Tree_High2(T));
	//Tree_levelSum(T);
	//pre_Noncirculate(T);
	//printf("%d%s", CountDoublesonNodes(T),"     ");
	//LevelOrder(SwapTree (T));
	//Find_Pre(T,5);
	//T=DeleteTree(T);
     //FindThenDelete(T, 9);
	  printf("\n");
	//pre_Noncirculate(T);
	//LevelOrder(T);
	//T = NULL;
	//printf("\n%p\n", T);
	//if (T!= NULL)
		//cout << "1w21";
	system("pause");
	return 0;
}
//*************************************************************************************************************
BiNode* Createtree(ElemType a[], int n1, int m1, ElemType b[], int n2, int m2)//根据先序和中序遍历结果创建唯一确定的二叉树
{
	BiNode* root = (BiNode*)malloc(sizeof(BiNode));
		root->data = a[n1];
	int i=0, llen=0, rlen=0;
	for (; b[i] != root->data ; i++);//找到根节点在中序序列的下标i;
	llen = i - n2;//左子树长
	rlen = m2 - i;//右子树长
	if (llen!=0)  //当左子树长不为零时建左子树
	     root->lchild = Createtree(a, n1 + 1, n1 + llen, b, n2, n2 + llen - 1);//新的建树序列(新的中序序列)对应b的起始下标n2,
	else                                                        //结束下标n2+len-1;新的参考序列(新的先序序列)对应a的起始坐标n1+1,结束坐标n1+len;
		 root->lchild = NULL;
	if (rlen != 0)//当右子树长不为零时建右子树
		root->rchild = Createtree(a, m1 - rlen + 1, m1, b, m2 - rlen + 1, m2);//新的建树序列(新的中序序列)对应b的起始下标m2-rlrn+1,
	else                                                                   //结束下标m2;新的参考序(新的先序序列)列对应a的起始坐标m1-rlen+1,结束坐标m1;
	     root->rchild = NULL;
	return root;
}
//*************************************************************************************************************
ThreadBiNode* CreateTree(ElemType a[], int n1, int m1, ElemType b[], int n2, int m2)//根据先序和中序遍历结果创建唯一确定的二叉树
{
	ThreadBiNode* root = (ThreadBiNode*)malloc(sizeof(ThreadBiNode));
	root->data = a[n1];
	root->ltag = root->rtag = 0;
	int i = 0, llen = 0, rlen = 0;
	for (; b[i] != root->data; i++);//找到根节点在中序序列的下标i;
	llen = i - n2;//左子树长
	rlen = m2 - i;//右子树长
	if (llen != 0)  //当左子树长不为零时建左子树
	{
		root->lchild = CreateTree(a, n1 + 1, n1 + llen, b, n2, n2 + llen - 1);//新的建树序列(新的中序序列)对应b的起始下标n2,
		root->ltag = root->rtag = 0;
	}
	else                                                        //结束下标n2+len-1;新的参考序列(新的先序序列)对应a的起始坐标n1+1,结束坐标n1+len;
	{
		root->lchild = NULL;
		root->ltag = root->rtag = 0;
	}
	if (rlen != 0)//当右子树长不为零时建右子树
	{
		root->rchild = CreateTree(a, m1 - rlen + 1, m1, b, m2 - rlen + 1, m2);//新的建树序列(新的中序序列)对应b的起始下标m2-rlrn+1,
		root->ltag = root->rtag = 0;
	}

	else                                                                   //结束下标m2;新的参考序(新的先序序列)列对应a的起始坐标m1-rlen+1,结束坐标m1;
	{
		root->rchild = NULL;
		root->ltag = root->rtag = 0;
	}
	return root;
}
//*************************************************************************************************************
void pre_Noncirculate(BiNode* T)    //先序遍历二叉树的非递归算法
{
	if (T == NULL)
		return;
	BiNode* stack[maxSize],*p=T; int top = -1;
	stack[++top] = p;
	while (top != -1)
	{
		p = stack[top--];
		printf("%d%s", p->data, "       ");
		if (p->rchild != NULL)
			stack[++top] = p->rchild;
		if (p->lchild != NULL)
			stack[++top] = p->lchild;

	}
}
//*************************************************************************************************************
void Inorder_Noncirculate(BiNode* T)  //中序遍历二叉树的非递归算法
{

	if(T==NULL)//如果树是空树,退出
		return;
	BiNode* stack[maxSize]; int top = -1;
	BiNode* p = T;//工作指针
	while (top != -1 || p != NULL)
	{
		if (p != NULL)
		{
			stack[++top] = p;
			p = p->lchild;
	  }
		else
		{
			p = stack[top--];
			printf("%d", p->data);
			p = p->rchild;
		}

 	}

}
//*************************************************************************************************************
void  Post_Noncirculate(BiNode* T)//后序遍历二叉树的非递归算法
{
	if (T == NULL)
		return;
	BiNode* stack[maxSize], * p = T,*r=NULL; int top = -1;//p是工作指针,r是辅助指针,指向最近访问过的结点
	while (p != NULL || top != -1)
	{
		if (p != NULL)   // 找到最左的结点
		{
			stack[++top] = p;
			p = p->lchild;
		}
		else
		{
			p =  stack[top];//取栈顶结点

			if (p->rchild!=NULL && p->rchild != r)//若右子树存在,且未被访问过
			{
				p = p->rchild;         //转向右子树
				stack[++top] = p;      //压入栈
				p = p->lchild;           //依旧往左走
			}      
			else //否则,弹栈并访问
			{
				p=stack[top--];    //弹出结点
				printf("%d%s", p->data,"    ");//访问结点
				r = p;             //记录最近访问过的结点
				p = NULL;          //结点访问完后,重置p指针
	   		}
		}
	}

}
//*************************************************************************************************************
int FindAncestorToChild(BiNode* T, ElemType X,BiNode *temp[])//求根节点到某一结点的路径,temp为辅助栈,用来存放祖先结点,返回辅助栈的栈顶指针
{
	if (T == NULL)
		exit(0);
	BiNode* stack[maxSize], * p = T, * r = NULL; //p是工作指针,r是辅助指针,指向最近访问过的结点
	int top = -1,topa=-1;//栈初始化
	while (p != NULL || top != -1)
	{
		if (p != NULL)   // 找到最左的结点
		{
			stack[++top] = p;
			p = p->lchild;
		}
		else
		{
			p = stack[top];//取栈顶结点
			if (p->rchild != NULL && p->rchild != r)//若右子树存在,且未被访问过
			{
				p = p->rchild;         //转向右子树
				stack[++top] = p;      //压入栈
				p = p->lchild;           //依旧往左走
			}
			else //否则,弹栈并访问
			{
				p = stack[top--];    //弹出结点
				if(p->data==X)       //访问到值为X的结点时,栈中结点是其所有祖先
				{
				while (top != -1)
				{
					temp[++topa] = p;     //将祖先结点压入辅助栈中
					p = stack[top--];
					
				}
				temp[++topa] = p;        //根节点入辅助栈
				}
				r = p;             //记录最近访问过的结点
				p = NULL;          //结点访问完后,重置p指针
			}
		}
	}
	return topa;
}
//*************************************************************************************************************
void  LevelOrder(BiNode* T)//二叉树层次遍历
{
	if (T == NULL)
		return ;
	BiNode* queue[maxSize],*p;//定义一个循环队列,还有一个工作指针p
	int front = 0, rear = 0;  //初始化循环队列
	queue[rear] = T;
	rear = (rear + 1) % maxSize;//根结点入队
	while (front != rear)      //队列不空时循环
	{
		p = queue[front];
		front = (front + 1) % maxSize;//队头元素出队
		printf("%d%s", p->data, "  ");  //访问出队元素 
		if (p->lchild != NULL)       //左子树不空则进队 
		{
			queue[rear] = p->lchild;  
			rear = (rear + 1) % maxSize;
		}
		if (p->rchild!= NULL)//右子树不空则进队
		{
			queue[rear] = p->rchild;
			rear = (rear + 1) % maxSize;
		}
	}
  }
//*************************************************************************************************************
void  LevelOrder2(ThreadBiNode* T)//二叉树层次遍历
{
	if (T == NULL)
		return;
	ThreadBiNode* queue[maxSize], * p;//定义一个循环队列,还有一个工作指针p
	int front = 0, rear = 0;  //初始化循环队列
	queue[rear] = T;
	rear = (rear + 1) % maxSize;//根结点入队
	while (front != rear)      //队列不空时循环
	{
		p = queue[front];
		front = (front + 1) % maxSize;//队头元素出队
		printf("%d%s", p->data, "  ");  //访问出队元素 
		if (p->lchild != NULL)       //左子树不空则进队 
		{
			queue[rear] = p->lchild;
			rear = (rear + 1) % maxSize;
		}
		if (p->rchild != NULL)//右子树不空则进队
		{
			queue[rear] = p->rchild;
			rear = (rear + 1) % maxSize;
		}
	}
}
//*************************************************************************************************************
int Tree_High(BiNode* T)  //求二叉树高度的非递归算法
{
	if (T == NULL)
		return 0;
	BiNode* queue[maxSize], * p;//定义一个循环队列,还有一个工作指针p
	int front = 0, rear = 0;  //初始化循环队列
	queue[rear] = T;
	rear = (rear + 1) % maxSize;//根结点入队
	int last = rear, level = 0;  //指针last指向当前层的最右结点,level是高度
	while (front != rear)      //队列不空时循环
	{
		p = queue[front];
		front = (front + 1) % maxSize;//队头元素出队
		if (p->lchild != NULL)       //左子树不空则进队 
		{
			queue[rear] = p->lchild;
			rear = (rear + 1) % maxSize;
		}
		if (p->rchild != NULL)//右子树不空则进队
		{
			queue[rear] = p->rchild;
			rear = (rear + 1) % maxSize;
		}
		if (front == last)    //如果当前层的所有的结点已出队则高度加一,且让last指针重新指向下一层的最右结点
		{
			level++;
			last = rear;
		}
	}
	return level;
}
//*************************************************************************************************************
int Tree_High2(BiNode* T)   //求二叉树高的递归算法
{
	if (T == NULL)
		return 0;
	int lefthigh = 0, righthigh = 0;
	lefthigh = Tree_High2(T->lchild);
	righthigh = Tree_High2(T->rchild);
	if (lefthigh > righthigh)
		return lefthigh + 1;
	else
		return righthigh + 1;
}
//*************************************************************************************************************
void Tree_levelSum(BiNode* T)  //求二叉树每层的结点个数
{
	if (T == NULL)
		return ;
	BiNode* queue[maxSize], * p;//定义一个循环队列,还有一个工作指针p
	int front = 0, rear = 0;  ///初始化循环队列
	int amount = 0, level = 0;     //定义amount存放每层结点数,level是高度
	queue[rear] = T;
	rear = (rear + 1) % maxSize;//根结点入队
	amount++;  //第一层结点数加一
	int last = rear;//指针last指向当前层的最右结点
	printf("%s%d%s%d%s", "第", 1, "层有", amount, "个结点"); //若树不空,第一层一定只有根节点一个结点
	amount = 0;//重新置为0,为下一层计数做准备
	printf("\n");
	while (front != rear)      //队列不空时循环
	{
		p = queue[front];
		front = (front + 1) % maxSize;//队头元素出队
		if (p->lchild != NULL)       //左子树不空则进队 
		{
			queue[rear] = p->lchild;
			rear = (rear + 1) % maxSize;
			amount++;               //有结点入队则当前层结点数加一
		}
		if (p->rchild != NULL)//右子树不空则进队
		{
			queue[rear] = p->rchild;
			rear = (rear + 1) % maxSize;
			amount++;              //有结点入队则当前层结点数加一
		}
		if (front == last)    //如果当前层的所有的结点已出队则高度加一,且让last指针重新指向下一层的最右结点
		{
			level++;          
			if(amount!=0)     //因为树的第一层被单独处理了,所以这里不加判断会多输出一次节点数为0的情况
			printf("%s%d%s%d%s", "第",level+1, "层有",amount,"个结点");
			last = rear;
			printf("\n");
			amount = 0;
		}

	}
}
//*************************************************************************************************************
void FindCommonAncestor(BiNode* T, ElemType x, ElemType y,BiNode *temp1[],BiNode *temp2[])//查找两个结点的最近公共祖先
{                                              
	int top1=FindAncestorToChild(T, x,temp1);
	int top2 = FindAncestorToChild(T, y, temp2);
	while (temp1[top1]->data== temp2[top2]->data)     //在两个栈中寻找最后一个相等的结点
	{
		top1--;
		top2--;
	}
	printf("%d", temp1[++top1]->data);         //两个栈顶指针和加一后都指向最近公共结点,任意选择一个打印
}
//*************************************************************************************************************
int CountDoublesonNodes(BiNode* T)   //统计一棵二叉树中双分支结点的个数
{
	static int count= 0;           //定义为静态变量使每次递归调用函数后count的值能传递到下一次调用
	if(T == NULL)
		return 0;
	else                          
	{
		CountDoublesonNodes(T->lchild);    //统计左子树双分支结点的个数
		if (T->lchild != NULL || T->rchild != NULL)   
			count++;
		CountDoublesonNodes(T->rchild);    //统计右子树双分支结点的个数
	}
	return count;
}
//*************************************************************************************************************
BiNode* SwapTree(BiNode* T)     //交换左右子树
{
	BiNode* temp = NULL;
	if (T != NULL)
	{
		temp = T->lchild;
		T->lchild = T->rchild;
		T->rchild = temp;
		SwapTree(T->lchild);
		SwapTree(T->rchild);
    }
	return T;
}
//*************************************************************************************************************
void Find_Pre(BiNode* T, int k) //找先序遍历序列中第k个结点的值
{
	static int count = 0;
	if (T != NULL)
	{
		if (++count == k)                //计数器的值等于k则找到结点
			printf("%d\n", T->data);
		Find_Pre(T->lchild, k);
		Find_Pre(T->rchild, k);
	}
}
//*************************************************************************************************************
void  DeleteTree(BiNode* T)    //删除一棵以T为根的二叉树
{
	if (T != NULL)
	{
		DeleteTree(T->lchild);          //先删除T的左子树
		DeleteTree(T->rchild);          //再删除T的右子树
		free(T);                        //最后释放T结点
		T = NULL;  //每释放一个以T指向的结点为根的子树时一定要将T指针置空
	}
}
//*************************************************************************************************************
void FindThenDelete(BiNode* T, ElemType x)    //在二叉树中查找所有结点值为x的结点,并删除以其为根的子树
{
	if (T == NULL)      //空树直接退出
		return;
	if (T->data == x)   //若根节点的值为x,则删除整棵树
	{
		DeleteTree(T);
		return;
	}
	BiNode* queue[maxSize], * p;//定义一个循环队列,还有一个工作指针p
	int front = 0, rear = 0;  //初始化循环队列
	queue[rear] = T;
	rear = (rear + 1) % maxSize;//根结点入队

	while (front != rear)      //队列不空时循环
	{
		p = queue[front];
		front = (front + 1) % maxSize;//队头元素出队
		if (p->lchild != NULL)       //左子树不空
		{
			if (p->lchild->data == x)   //若左子树的结点值等于x则删除左子树
			{
				DeleteTree(p->lchild);
				p->lchild = NULL;
			}
			else                       //否则入队
			{
				queue[rear] = p->lchild;
				rear = (rear + 1) % maxSize;
			}
		}
		if (p->rchild != NULL)//右子树不空
		{
			if (p->rchild->data == x)//右子树的结点值等于x则删除右子树
			{
				DeleteTree(p->rchild);
				p->rchild = NULL;
			}
			else                      //否则入队
			{
				queue[rear] = p->rchild;
				rear = (rear + 1) % maxSize;
			}
		}
	}
}
//*************************************************************************************************************
void InThread(ThreadBiNode  *&p, ThreadBiNode*& pre)
{
	if (p!= NULL)
	{
		InThread(p->lchild, pre);
		if (p->lchild == NULL)
		{
			p->lchild = pre;
			p->ltag = 1;
		}
		if (pre!=NULL&&pre->rchild==NULL)
		{
			pre->rchild = p;
			pre->rtag = 1;
		}
		pre = p;
		InThread(p->rchild, pre);
	}
}
//*************************************************************************************************************
void CreateInThread(ThreadBiNode* T)
{
	ThreadBiNode* pre = NULL;
	if (T != NULL)
	{
		InThread(T, pre);
		pre->rchild = NULL;
		pre->rtag = 1;
	}
}
//*************************************************************************************************************
ThreadBiNode* FirstNode(ThreadBiNode* p)
{
	while (p->ltag == 0)
		p = p->lchild;
	return p;
}
//*************************************************************************************************************
ThreadBiNode* NextNode(ThreadBiNode* p)
{
	if (p->rtag == 0)
		return  FirstNode(p->rchild);
	else
		return p->rchild;
}
//*************************************************************************************************************
void ThreadInOrder(ThreadBiNode* T)
{
	for (ThreadBiNode* p = FirstNode(T); p != NULL; p = NextNode(p))
		printf("%d\n", p->data);
}
//*************************************************************************************************************
ThreadBiNode* InPostPre(ThreadBiNode* T, ThreadBiNode* p)//在中序线索树上求指定结点在后序前驱结点
{
	ThreadBiNode* q=NULL;
	if (p->rtag == 0)//若p有右子女,则右子女是其后序前驱
		q = p->rchild;
	else if (p->ltag == 0)//若p有左子女,则左子女是其后序前驱
		q = p->lchild;
	else                 //若p既无左子女又无右子女,则沿左线索链寻找p结点第一个出现左子女的双亲结点
	{
		while (p != NULL && p->ltag == 1)//直到双亲有左子女
			p = p->lchild;
		if (p != NULL)              //双亲存在则p结点的后序前驱是其左子女
			q = p->lchild;
	}
	return q;
}
//*************************************************************************************************************

 

 
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值