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

二叉树的基本操作

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

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

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;  
} 

本人才疏学浅,如有错误,欢迎大家指正

发布了26 篇原创文章 · 获赞 9 · 访问量 8155

猜你喜欢

转载自blog.csdn.net/ParadiseHeaven/article/details/78593117