头文件,公用的结构内型 和相关函数的声明
#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);
}