二叉树的操作


头文件,公用的结构内型 和相关函数的声明

#ifndef BITREEEX_H
#define BITREEEX_H
#define  MaxSize 50
#include <iostream>

using namespace std;
typedef char ElemType;

typedef struct BiTreeEx
{
	ElemType data;
	struct BiTreeEx * pLeft;
	struct BiTreeEx * pRight;
}TREE, *pTREE, BITREEEX, *pBITREEEX;

void InitTree(pTREE *);
void CreatTree(pTREE *);
void PreTraverse(pTREE );
void InTraverse(pTREE );
void PostTraverse(pTREE );
pTREE SearchNode(pTREE , ElemType);
void DispLeaf(pTREE);  //输出所有叶子节点的元素值
void NoRevPreTrav(pTREE);  //非递归先序遍历


void CreatTreeEx(pBITREEEX &);
void NoRevPreTravEx(pBITREEEX);
void NoRevInTravEx(pBITREEEX);
void NoRevPostTravEx(pBITREEEX);
void NoRevPreTravEx1(pBITREEEX);
void NoRevInTravEx1(pBITREEEX);
void NoRevPostTravEx1(pBITREEEX);
int GetMaxDistance(pBITREEEX , int &, int &);
int Max(int , int );

void RevExchangeChild(pBITREEEX);
void NoRevExcChild(pBITREEEX);



#endif

一、树的创建

      两种创建数的方式:一种是用接受字符,用#结束;另一种是借用括号来操作

void CreatTree(pTREE *pT)
{
	ElemType data;
	cin >> data;
	
	if (data == '#')  //用来结束数在该节点的分支,然后该节点就成为了叶子节点
	{
		*pT = NULL;
	} 
	else
	{
		*pT = new TREE;
		(*pT)->data = data;
		CreatTree(&(*pT)->pLfet);
		CreatTree(&(*pT)->pRight);
	}	
}


 

/************************************************************************/
/*创建二叉树
用ch来扫描用括号表示的二叉树字符串:
(1)若ch = ‘(’:表示前面创建的节点作为双亲节点入栈,并置k = 1,表示其后创建的节点作为子节点
(2)若ch = ‘)’:表示栈中的节点的左右孩子都处理完,退栈
(3)若ch = ‘,’:表示其后创建的节点有右孩子节点
(4)其它:表示要创建一个节点,并根据k值简历与栈中的联系
           k = 1 , 表示这个节点作为栈中节点的左孩子
		   k = 2 , 表示这个节点作为栈中节点的右孩子
		   这样处理整个字符串,创建二叉树
*/
/************************************************************************/
void CreatTreeEx(pBITREEEX &pT)
{
	pBITREEEX stack[MaxSize];
	pBITREEEX p = NULL;

	char str[MaxSize] = "A(B(D(,G)),C(E,F))";
	//cout <<"请输入你要造数的字符串:";
	//cin  >> str;


	int top = -1;
	int k, j = 0;
	char ch;
	ch = str[j];
	pT = NULL;
	while (ch != '\0')
	{
		switch (ch)
		{
		case '(': top++;
			      stack[top] = p;
				  k = 1;
			      break;
		case ')': top--;
			      break;
		case ',': k = 2;
			      break;
		default: p = new BiTreeEx;
			     p->data = ch;
				 p->pLeft = p->pRight = NULL;
				 if (pT == NULL)
				 {
					 pT = p;
				 } 
				 else
				 {
					 switch (k)
					 {
					 case 1 :stack[top]->pLeft = p;break;
					 case 2 :stack[top]->pRight = p;break;
					 }
				 }
		}
		j++;
		ch = str[j];
	}

}


二、数的遍历

       1、递归的三种遍历

  

void PreTraverse(pTREE pT)
{
	if (pT)
	{
		cout << pT->data << "   ";
		PreTraverse(pT->pLfet);
		PreTraverse(pT->pRight);
	}	
}

void InTraverse(pTREE pT)
{
	if (pT)
	{
		InTraverse(pT->pLfet);
		cout << pT->data << "   ";
		InTraverse(pT->pRight);
	}	
}

void PostTraverse(pTREE pT)
{
	if (pT)
	{
		PostTraverse(pT->pLfet);
		PostTraverse(pT->pRight);
		cout << pT->data << "   ";
	}
	
}


        2、非递归的遍历

/************************************************************************/
/* 
使用非递归实现二叉树的遍历:(运用一个静态是指针数组来模拟一个堆栈,top相当有这个栈的栈顶指针)
(1)先将根节点入栈,并设置一个tag = 1,作用是引导进入下面的循环,不是访问权限的设置
(2)只要栈不为空,往下走,直到栈为空是结束~~
(3)如果栈顶元素未访问过(就是tag值为1)
      首先是在退栈,退出父节点(已经遍历了),下一个就是左子树,如果左子树为空遍历右子树,否则继续遍历左子树,
	  就是先序递归遍历的思想
*/
/************************************************************************/
void NoRevPreTravEx(pBITREEEX pT)
{
	pBITREEEX p;
	struct
	{
		pBITREEEX pt;
		int tag;
	}stack[MaxSize];
	int top = -1;
	top ++;
	stack[top].pt = pT;
	stack[top].tag = 1;   //第一个根节点特殊  tag = 1,是为了引导进入while中的if 在后面会有入栈的
	while (top > -1)
	{
		if (stack[top].tag == 1)   //不能直接访问
		{
			p = stack[top].pt;
			top--;
			if (p != NULL)
			{
				top++;
				stack[top].pt = p->pRight;    //右孩子入栈,设为不能直接访问
				stack[top].tag = 1;

				top ++;
				stack[top].pt = p->pLeft;     //左孩子入栈,设为不能直接访问
				stack[top].tag = 1;

				top++;
				stack[top].pt = p;            //根入栈,设为可直接访问
				stack[top].tag = 0;
			}
		}
		if (stack[top].tag == 0)             //访问可直接访问的元素,并出栈
		{
			cout << stack[top].pt->data << "   ";
			top--;
		}
	}//while
	cout << endl;
}
/************************************************************************/
/* 另一种非递归,思路是一样的,只是表示方法有些不同而已
                                                                     */
/************************************************************************/
void NoRevPreTravEx1(pBITREEEX pT)
{
	pBITREEEX stack[MaxSize];
	pBITREEEX p ;
	int top = -1;
	if (pT != NULL)
	{
		top++;          //根节点入栈
		stack[top] = pT;
		while (top >= 0)
		{
			p = stack[top];              //当前根节点出栈,并访问该节点
			top--;
			cout << p->data << "   ";

			if (p->pRight != NULL)          //右孩子入栈
			{
				top++;
				stack[top] = p->pRight;
			}
			if (p->pLeft != NULL)           //左孩子入栈
			{
				top++;
				stack[top] = p->pLeft;
			}
		}
		cout << endl;
	}//while
}


/************************************************************************/
/*
中序遍历,思路与先序是一样的,只是栈的压入顺序不一样,其它的都是一样的
 
*/
/************************************************************************/
void NoRevInTravEx(pBITREEEX pT)
{
    pBITREEEX p;
	struct
	{
		pBITREEEX pt;
		int tag;
	}stack[MaxSize];
	
	//pBITREEEX p = NULL;    //这个必须放到上面定义的结构体上去,否则运行时会死掉  为什么?????
    //经过测试好像是vc++6.0编译器的原因,可以使内存分配的不一样,但是真的感觉不科学啊  gcc很好没有任何异常
	int top = -1;
	top++;
	stack[top].pt = pT;
	stack[top].tag = 1;

	while (top > -1)
	{
		if (stack[top].tag == 1)    //没有访问的节点
		{
			p = stack[top].pt;
			top--;
			if (p != NULL)
			{
				top++;
				stack[top].pt = p->pRight;
				stack[top].tag = 1;

				top++;
				stack[top].pt = p;
				stack[top].tag = 0;

				top++;
				stack[top].pt = p->pLeft;
				stack[top].tag = 1;
			}
		}
		if (stack[top].tag == 0 )
		{
			cout << stack[top].pt->data << "   ";
			top--;
		}
	}//while
	cout << endl;
}


/************************************************************************/
/*一样形式的后序遍历    
                                                        */
/************************************************************************/
void NoRevPostTravEx(pBITREEEX pT)
{
	pBITREEEX p;
	struct
	{
		pBITREEEX pt;
		int tag;
	}stack[MaxSize];
	int top = -1;
	top ++;
	stack[top].pt = pT;
	stack[top].tag = 1;   //第一个根节点特殊  tag = 1,是为了引导进入while中的if 在后面会有入栈的
	while (top > -1)
	{
		if (stack[top].tag == 1)   //不能直接访问
		{
			p = stack[top].pt;
			top--;
			if (p != NULL)
			{
				top++;
				stack[top].pt = p;            //根入栈,设为可直接访问
				stack[top].tag = 0;

				top++;
				stack[top].pt = p->pRight;    //右孩子入栈,设为不能直接访问
				stack[top].tag = 1;
				
				top ++;
				stack[top].pt = p->pLeft;     //左孩子入栈,设为不能直接访问
				stack[top].tag = 1;
				
			}
		}
		if (stack[top].tag == 0)             //访问可直接访问的元素,并出栈
		{
			cout << stack[top].pt->data << "   ";
			top--;
		}
	}//while
	cout << endl;
}


三、交换左右孩子(分有递归和非递归两种方式)

#include "BiTreeEx.h"
#include <queue>

/************************************************************************/
/* 
用递归的方式交换左右孩子
*/
/************************************************************************/
void RevExchangeChild(pBITREEEX pT)
{
	if ( NULL == pT)
	{
		return;
	}
	 pBITREEEX pTem = pT->pLeft;
	 pT->pLeft = pT->pRight;
	 pT->pRight = pTem;

	 RevExchangeChild(pT->pLeft);
	 RevExchangeChild(pT->pRight);
}

/************************************************************************/
/* 
  用非递归的方式交换左右孩子(借用C++ STL中的queue)
  (1)如果父节点不为空,将节点放入队列中, 否则返回
 (2)从队列取出一个节点,交换这个节点的左右孩子
 (3)如果分别判断左右孩子是否为空,不为空就分别入队
 (4)重复(2)(3)直到队列为空
 
*/
/************************************************************************/
void NoRevExcChild(pBITREEEX pT)
{
	if (NULL == pT)
	{
		return;
	}
	queue<pBITREEEX> qu;
	qu.push(pT);
	pBITREEEX pTreeMove;
	while (!qu.empty())
	{
		pTreeMove = qu.front();
		qu.pop();

		pBITREEEX pTem = pTreeMove->pLeft;
		pTreeMove->pLeft = pTreeMove->pRight;
		pTreeMove->pRight = pTem;

		if (NULL != pTreeMove->pLeft)
		{
			qu.push(pTreeMove->pLeft);
		}
		if (NULL != pTreeMove->pRight)
		{
			qu.push(pTreeMove->pRight);
		}
	}//end while

}


 

四、最大距离的获取

#include "BiTreeEx.h"

int Max(int a, int b)
{
	return a > b ? a : b;
}
int GetMaxDistance(pBITREEEX pT, int &maxLeft, int &maxRight)
{
	//maxLeft为左子树节点距离根节点最远的距离
	//maxRight为右子树节点距离根节点最远的距离
	if (pT == NULL)
	{
		maxLeft = 0;
		maxRight = 0;
		return 0;
	}

	/*
	maxDistLeft为左子树中节点间的最大距离
	maxDistRight为右子树中节点间的最大距离
	*/
	int maxLL, maxLR, maxRL, maxRR;
	int maxDistLeft, maxDistRight;
	if (pT->pLeft != NULL)
	{
		maxDistLeft = GetMaxDistance(pT->pLeft, maxLL, maxLR);
		maxLeft = Max(maxLL , maxLR) + 1;
	}
	else
	{
		maxDistLeft = 0;
		maxLeft = 0;
	}

	if (pT->pRight != NULL)
	{
		maxDistRight = GetMaxDistance(pT->pRight , maxRL, maxRR);
		maxRight = Max(maxRL , maxRR) + 1;
	}
	else
	{
		maxDistRight = 0;
		maxRight = 0;
	}

	return Max(Max(maxDistLeft, maxDistRight) , maxLeft+maxRight);
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值