二叉树

二叉树

记录

第三次学习二叉树了,对层次遍历,非递归遍历有了进一步的认识.

二叉树的性质

  • 在二叉树的第n层上最多有2n-1个结点
  • 深度为k的二叉树最多有2k-1个结点(k>=1)
  • 对于任何一个二叉树T,度为0的结点数为n0,度为2的结点数为n2 则n0=n2+1

解释:有n个结点的二叉树,除了根节点,其他每个结点都对应一条连线.所以由 n-1条线. 而度为2的对应两条连线,度为1的对应1条连线.所以 n-1 =n2*2+n1.
n个结点包括度分别为0,1,2的结点.所以n =n1+n2+n0 综合两个公式得出 n0 = n2+1

  • 具有n个结点的完全二叉树的深度为[log2n]+1 ([x]表示不大于x的最大整数
  • 如果有一颗有n个节点的完全二叉树的节点按层次序编号,对任一层的节点i(1<=i<=n)有
    • 如果i=1,则节点是二叉树的根,无双亲,如-果i>1,则其双亲节点为[i/2],向下取整
    • 如果2i>n那么节点i没有左孩子,否则其左孩子为2i
    • 如果2i+1>n那么节点没有右孩子,否则右孩子为2i+1

实现代码©

将代码分开来放了,方便和其他配合着用,开始用的自己写的栈,后来用STL的栈和队列了.

/*
bTree.h
*/
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <stack>
#include <queue>

using namespace std;
typedef char ElemType;
#define MAXSIZE 100
//定义二叉树结点
typedef struct BtNode {
	ElemType data;
	struct BtNode *lchild, *rchild;
}BtNode, *BTree;

//创建二叉树.使用#表示结点为空
void CreateBTree(BTree &BT);
//访问结点并输出
void visit(BTree bt);
//前序遍历
void PreNode(BTree bt);
//前序遍历(栈)
void PreOrder(BTree bt);
//度为2的结点数
int leaf_2(BTree bt);
//树的深度
int  len_tree(BTree bt);
//二叉树的层次遍历
void LevelOrder(BTree bt);
//后续遍历(栈)
void LastOrder(BTree bt);
//二叉树 自下向上,自右向左
void BottomLevelOrder(BTree bt);

//非递归方式求树的深度
int BtDepth(BTree &bt);
//根据先序遍历和中序遍历求二叉树.
BTree PreInCreate(ElemType A[], ElemType B[],
	int l1, int r1, int l2, int r2);

//判定二叉树是否是完全二叉树
//采用层次遍历,遇到空,看队列后面是否还有非空结点
bool isCompleteTree(BTree bt);
//将树中所有节点的左,右子树进行交换的函数
void SwapLeftRight(BTree bt);

//对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间.
void DelChildByX(BTree bt, ElemType x);

void FindXAncestor(BTree bt, ElemType x);

/*求非空二叉树b的宽度,
用层次遍历的方式,
*/
int MaxWidth(BTree bt);
/*
bTree.cpp
*/
#include "bTree.h"

//创建二叉树.使用#表示结点为空
void CreateBTree(BTree &BT) 
{
	ElemType data;
	scanf_s("%c", &data);
	if (data == '#') {
		BT = NULL;
	}
	else
	{
		BT = (BTree)malloc(sizeof(BtNode));
		BT->data = data;
		CreateBTree(BT->lchild);
		CreateBTree(BT->rchild);
	}
}

//访问结点并输出
void visit(BTree bt)
{
	if (bt->data != NULL){
		printf("%2c", bt->data);
	}
}
//前序遍历
void PreNode(BTree bt)
{
	if (bt != NULL)
	{
		visit(bt);
		PreNode(bt->lchild);
		PreNode(bt->rchild);
	}
}
//前序遍历(栈)非递归方式
void PreOrder(BTree bt)
{
	stack<BtNode *> S;
	BtNode *p = bt;
	while (p || !S.empty()){ 
		if (p){	 
			visit(p);
			S.push(p);
			p = p->lchild;
		}
		else
		{
			p = S.top();
			S.pop();
			p = p->rchild;
		}
	}
}
//后续遍历(栈)
void LastOrder(BTree bt)
{
	stack<BtNode *> S;
	BtNode *p = bt, *r = NULL; //r指向最近访问过的结点
	while (p || !S.empty())
	{
		if (p){  //走到最左边
			S.push(p);
			p = p->lchild;
		}
		else{
			p=S.top();
			if (p->rchild &&p->rchild != r){ //右子树不为空,且未被访问过
				p = p->rchild;
				S.push(p);
				p = (*p).lchild;
			}
			else
			{
				visit(p);
				r = p;
				S.pop();
				p = NULL;
			}
		}
	}
}


//中序遍历
void InNode(BTree bt)
{
	if (bt != NULL)
	{
		InNode(bt->lchild);
		visit(bt);
		InNode(bt->rchild);
	}
}
//后序遍历
void LastNode(BTree bt)
{
	if (bt != NULL)
	{
		LastNode(bt->lchild);
		LastNode(bt->rchild);
		visit(bt);
	}
}

//二叉树的层次遍历,层次遍历使用队列.
void LevelOrder(BTree bt)
{
	queue<BtNode *> Q; //stl的队列
	BtNode *p = bt;
	Q.push(p);	//根结点如队列
	while (!Q.empty()){ //队列不为空
		p = Q.front();
		Q.pop();
		visit(p);
		if (p->lchild != NULL)
			Q.push(p->lchild);
		if (p->rchild != NULL)
			Q.push(p->rchild);
	}
}
//二叉树 自下向上,自右向左访问二叉树
void BottomLevelOrder(BTree bt)
{
	queue<BtNode *>Q;
	stack<BtNode *>S;
	BtNode *p=bt;
	Q.push(p);
	while (!Q.empty()){
		p = Q.front();
		Q.pop();
		S.push(p);
		if (p->lchild != NULL)
			Q.push(p->lchild);
		if (p->rchild != NULL)
			Q.push(p->rchild);
	}
	while (!S.empty()){
		p=S.top();
		S.pop();
		visit(p);
	}
}
/*非递归方式求二叉树的高度
	用层次遍历来求.
*/
int BtDepth(BTree &bt)
{
	if (!bt)
		return 0;
	BTree p;
	int front = 0, rear = 0;
	BtNode * Q[MAXSIZE];	//循环队列
	Q[rear] = bt;		//根节点入队
	rear = (rear + 1) % MAXSIZE;
	int last = 1, level = 0; //last指向下一层第一个结点的位置.
	while (front != rear){
		p = Q[front];		//出队列
		front = (front + 1) % MAXSIZE;
		if (p->lchild){	//左子树存在,左子树入队列
			Q[rear] = p->lchild;
			rear = (rear + 1) % MAXSIZE;
		}
		if (p->rchild){
			Q[rear] = p->rchild;
			rear = (rear + 1) % MAXSIZE;
		}
		if (front == last){
			level++;
			last = rear;
		}
	}
	return level;

}

/*求非空二叉树b的宽度,
用层次遍历的方式,
*/
int MaxWidth(BTree bt)
{
	if (!bt)
		return 0;
	BtNode * Q[MAXSIZE];
	BTree p = NULL;
	int front = 0, rear = 0;
	int maxwidth = 0;
	int num = 1;
	Q[rear] = bt;	//根节点入队列
	rear =(rear + 1) % MAXSIZE; //指向队列下一个空位置.
	int last = 1; //last指向下一层第一个结点.
	while (front != rear){  //队列不为空
		p = Q[front]; //出队列
		front = (front + 1) % MAXSIZE;
		if (p->lchild){ //左子树存在
			Q[rear] = p->lchild;
			rear = (rear + 1) % MAXSIZE;
		}
		if (p->rchild){
			Q[rear] = p->rchild;
			rear = (rear + 1) % MAXSIZE;
		}
		if (last != front){
			num++;
		}
		else{		//last==front 说明一层扫描结束了
			if (num > maxwidth)
				maxwidth = num;
			num = 1;
			last = rear;
		}
	}
	return maxwidth;
}
//树的深度
int  len_tree(BTree bt)
{
	int dl, dr, len;
	if (bt == NULL){
		return 0;
	}
	else
	{
		dl = len_tree(bt->lchild);
		dr = len_tree(bt->rchild);
		len = (dl >= dr) ? dl : dr;
		return len + 1;
		
	}
}

//度为2的结点数
int leaf_2(BTree bt)
{
	if (bt == NULL) return 0;
	if (bt->lchild != NULL && bt->rchild != NULL)
	{
		return 1 + leaf_2(bt->lchild) 
			+ leaf_2(bt->rchild);
	}
	return leaf_2(bt->lchild) + leaf_2(bt->rchild);
}
//度为0的结点数
int leaf_0(BTree bt)
{
	if (bt == NULL) return 0;
	if (bt->lchild == NULL && bt->rchild == NULL)
	{
		return 1;
	}

	return leaf_0(bt->lchild) + leaf_0(bt->rchild);
}

//根据先序遍历和中序遍历求二叉树.
BTree PreInCreate(ElemType A[], ElemType B[], 
	int l1, int r1, int l2, int r2)
{
	int i;
	BTree root = (BtNode *)malloc(sizeof(BtNode));
	root->data = A[l1];
	for (i = l2; B[i] != root->data; i++);
	int llen = i - l2;
	int rlen = r2 - i;
	if (llen)
		root->lchild = PreInCreate(A, B,
		l1 + 1, l1 + llen, l2, l2 + llen - 1);
	else
		root->lchild = NULL;
	if (rlen)
		root->rchild = PreInCreate(A, B,
		r1 - rlen + 1, r1, r2 - rlen + 1, r2);
	else
		root->rchild = NULL;
	return root;
}

//判定二叉树是否是完全二叉树
//采用层次遍历,遇到空,看队列后面是否还有非空结点
bool isCompleteTree(BTree bt)
{
	queue <BtNode *> Q;
	BtNode * p = bt;
	Q.push(p);
	while (!Q.empty()){
		p = Q.front();
		Q.pop();
		if (p){
			Q.push(p->lchild);
			Q.push(p->rchild);
		}
		else{
			while (!Q.empty()){
				p = Q.front();
				Q.pop();
				if (p)
					return 0;
			}
		}
	}
	return 1;
}

//将树中所有节点的左,右子树进行交换的函数
void SwapLeftRight(BTree bt)
{
	if (bt ==NULL)
		return;
	BtNode *p = NULL;
	p = bt->lchild;
	bt->lchild = bt->rchild;
	bt->rchild = p;
	SwapLeftRight(bt->lchild);
	SwapLeftRight(bt->rchild);
}

//------------------------------------
//对于树中每个元素值为x的结点,删去以它为根的子树,并释放相应的空间.

void Delchild(BTree bt)
{
	if (bt){
		Delchild(bt->lchild);
		Delchild(bt->rchild);
		free(bt);
	}
}

void DelChildByX(BTree bt, ElemType x)
{
	//用层次遍历的方法查找值为x的结点
	queue <BtNode *>Q;
	BtNode *p=NULL;
	int flag = 0;//保存是否找到x结点.
	Q.push(bt);
	while (!Q.empty()){
		p = Q.front();
		Q.pop();
		if (p->data == x){
			flag = 1;
			break;
		}
		if (p->lchild !=NULL)
			Q.push(p->lchild);
		if (p->rchild !=NULL)
			Q.push(p->rchild);
	}
	if (flag == 1){
		Delchild(p->lchild); //删除该结点的左子树
		p->lchild = NULL;
		Delchild(p->rchild); //删除该结点的右子树
		p->rchild = NULL;
	}
	else
		return;
}

/*查找值为x的结点,打印值为x的结点的所有祖先.
用 非递归方式(栈) 后序遍历,栈中的所有节点就是x的祖先结点.
*/
void FindXAncestor(BTree bt, ElemType x)
{
	stack <BtNode *> S;
	BtNode * p = bt, *r = NULL;
	while (p || !S.empty()){
		if(p){
			if (p->data == x)
				break;
			S.push(p);
			p = p->lchild;
		}
		else{
			p = S.top();
			if (p->data == x)
				break;
			if (p->rchild&& p->rchild != r){
				p = p->rchild;
				S.push(p);
				p = p->lchild;
			}
			else{
				S.pop();
				r = p;
				p = NULL;
			}

		}
	}
	if (p && p->data == x){
		while (!S.empty()){
			p = S.top();
			visit(p);
			S.pop();
		}
	}
}

/*main.cpp*/
#include <stdio.h>
#include <iostream>
#include <cstdlib>
#include <time.h>
#include "bTree.h"

using namespace std;
int main(){
	BTree bt;
	printf("先序建立一棵二叉树:\n");
	CreateBTree(bt);
	cout << endl;
	printf("层次遍历:\n");
	LevelOrder(bt);
	cout << endl;
	cout <<	MaxWidth(bt);
	system("pause");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值