您的位置:首页 > 其它

二叉树的基本操作(总结)

2017-11-21 23:05 351 查看

二叉树的基本操作

二叉树的定义决定了其大多数操作都可以由递归去实现

本文通过递归和非递归两种方式实现二叉树的基本操作(加深对原理的理解)

1.二叉树的声明

typedef char ElementType;
typedef struct TreeNode* BinTree;
struct TreeNode{
ElementType Data;
struct TreeNode* Left;
struct TreeNode* Right;
};


2.遍历

(1)递归实现

>1  先序遍历

按照“根节点-左儿子-右儿子”的顺序访问

void PreorderTraversal(BinTree BT) {
if (!BT) return;    //空树,直接返回
visit(BT->Data);
PreorderTraversal(BT->Left);    //递归遍历左子树
PreorderTraversal(BT->Right);   //递归遍历右子树
}


>2  中序遍历

按照“左儿子-根节点-右儿子”的顺序访问

void InorderTraversal(BinTree BT){
if(!BT) return ;
InorderTraversal(BT->Left);
visit(BT->Data);
InorderTraversal(BT->Right);
}

 >3  后序遍历

按照“左儿子-右儿子-根节点”的顺序访问

void PostorderTraversal(BinTree BT){
if(!BT) return ;
InorderTraversal(BT->Left);
InorderTraversal(BT->Right);
visit(BT->Data);
}


(2)非递归实现(二叉树的非递归实现借助栈来实现)

属于哪种遍历取决于根节点第几次遇到时访问

>1  先序遍历(首次遇到时访问)

//C语言实现
int MaxSize = 1000;
void PreorderTraversalRecur(BinTree BT) {
TreeNode* St[MaxSize], *p;	//创建一个栈
int top = -1;	//top的下一个位置指向栈顶
if (!BT) {
St[++top] = BT;	//根节点入栈
while (top > -1) {
p = St[top];
top--;
printf("%c ", p->Data);	//先序遍历,第一次遇到(入栈)时就访问
//左右子树压栈
if (!p->Left) 	St[++top] = p->Left;
if (!p->Right) 	St[++top] = p->Right;
}
}
}


//C++实现
void PreOrderTraversal(BinTree BT) {
if (!BT)   return;
stack<BinTree> s;
BinTree temp;
s.push(BT);
while (!s.empty()) {
temp = s.top();
printf("%c ", temp->Data);
s.pop();
if (temp->Left)		s.push(temp->Left);
if (temp->Right)	s.push(temp->Right);
}
}


>2  中序遍历

void InorderTraversal(BinTree BT) {
TreeNode *St[MaxSize], *node;
int top = -1;
if (!BT) {
node = BT;
while (top > -1 || node != NULL) {
//先把所有的左子树压栈
while (node != NULL) {
St[++top] = node;
node = node->Left;
}
//回溯,访问最后入栈的结点的右子树
if (top > -1) {
node = St[top--];	//取除栈顶元素,并且top--
printf("%c ", node->Data);	//此时第二次遇到根节点,访问
node = node->Right;
}
}
}
}


void InOrderTravel(BinTree BT) {
if (!BT)   return;
stack<BinTree> s;
BinTree node = BT;
while (!node || !s.empty()) {
while (!s.empty() || node) {
//一直遍历到左子树最下边,边遍历边保存根节点到栈中
while (node) {
s.push(node);
node = node->Left;
}
//当p为空时,说明已经到达左子树最下边,这时需要出栈了
if (!s.empty()) {
node = s.top();
s.pop();
printf("%c ", node->Data);
//进入右子树,开始新的一轮左子树遍历(这是递归的自我实现)
node = node->Right;
}
}
/*
//另解
while (!s.empty() || node) {
if (node) {
s.push(node);
node = node->Left;
}
else {
node = s.top();
s.pop();
printf("%c ", node->Data);
node = node->Right;
}
}
*/
}
}


>3  后序遍历

//C++实现
void PostorderTraversalRecursion(BinTree BT) {
if (!BT)	return;
stack<BinTree> s;
//pCur:当前访问节点,pLast:上次访问节点
BinTree pCur, pLast;
pCur = BT;
pLast = NULL;
//把左子树结点全部压栈
while (pCur) {
s.push(pCur);
pCur = pCur->Left;
}
//已经遍历到左子树底端
while (!s.empty()) {
pCur = s.top();
s.pop();

if (pCur->Left == pLast) {	//若左子树刚被访问过,则需先进入右子树(根节点需再次入栈)
//根节点再次入栈
s.push(pCur);
//进入右子树,且可肯定右子树一定不为空
pCur = pCur->Right;
while (pCur) {
s.push(pCur);
pCur = pCur->Right;
}
}
//一个根节点被访问的前提是:无右子树或右子树已被访问过
else if (pCur->Right == NULL || pCur->Right == pLast) {
printf("%c ", pCur->Data);
//修改最近被访问的节点
pLast = pCur;
}
}
}


参考:http://blog.csdn.net/zhangxiangdavaid/article/details/37115355

层序遍历(利用队列实现)

>1   C语言实现队列

void LevelorderTraversal(BinTree BT) {
BinTree q[1000];
BinTree temp;
int head = 0, tail = 0;
if (!BT) return;
else {
q[tail++] = BT;
while (tail != head) {
temp = q[head++];
printf(" %c", temp->Data);
if (temp->Left)     q[tail++] = temp->Left;
if (temp->Right)    q[tail++] = temp->Right;
}
}
}


2>   C++(queue)实现

void LevelorderTraversal(BinTree BT) {
queue <BinTree> q;
BinTree temp;
if (!BT) return;
else {
q.push(BT);	//根节点入队
while (!q.empty()) {
temp = q.front();
q.pop();	//队首元素出队,并访问
cout << temp->Data << ' ';
if (temp->Left)    q.push(temp->Left);	//左儿子入队
if (temp->Right)   q.push(temp->Right);	//右儿子入队
}
}
}


3.其他操作

(1)求树的高度

int GetHeight(BinTree BT) {
/*
if (BT == NULL)
return 0;
else return 1 +(GetHeight(BT->Left) > GetHeight(BT->Right) ? GetHeight(BT->Left): GetHeight(BT->Right));
*/

int h = 0;
if (BT == NULL) {
return 0;
}
int lh = GetHeight(BT->Left) + 1;
int rh = GetHeight(BT->Right) + 1;

h = lh > rh ? lh : rh;
return h;
}

(2)求二叉树结点的个数

int Nodenum(BinTree BT)  {
if(!BT)  return 0;
else    return 1+Nodenum(BT->Left)+Nodenum(BT->Right);
}

(3)求叶子结点的个数

int LeavesCount(BiTree BT)  {
if(!BT == NULL)   return 0;   //BT为空树,返回0

int cnt = 0;
if(!(BT->LChild || BT->RChild))  ++cnt;   //BT为叶子结点,加1
else {
//递归求左子树上的叶子结点,并累加
cnt += LeavesCount(BT->LChild);
//递归求右子树上的叶子结点,并累加
cnt += LeavesCount(BT->RChild);
}
return cnt;
}


本人才疏学浅,如有错误,欢迎大家指正
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: