二叉树代码详解 ,看了直接会实现二叉树!!!

二叉树纯代码详解 ,看了直接会实现二叉树!!!


1.基本结构

2.基本函数代码实现

3.函数的具体实现,解释在代码里面

1.基本结构

结点构成(一个数据区域,两个左右指针),每一个结点都只有唯一父母,两个孩子
在这里插入图片描述
在这里插入图片描述

2.基本函数代码实现…

//二叉树的创建
bool CreatBiTree(BiTree& T);

//二叉树的销毁
bool DestroyBiTree(BiTree &T);

//二叉树的节点总数
int BiNodeCount(BiTree T);

//二叉树的叶子节点个数
int BiNodeLeafCount(BiTree T);

//二叉树的深度
int BiNodeDepth(BiTree T);

//前序遍历
bool BiTreePreOrder(BiTree& T);

//中序遍历
bool BiTreeInOrder(BiTree T);

//后序遍历
bool BiTreePostOrder(BiTree T);

//层次遍历需要队列
bool LevelOrder(BiTree T);

//是否是完全二叉数
bool BiTreeComplete(BiTree T);

3.函数的具体实现,解释在代码里面

3.1二叉树的创建
//二叉树的创建
bool CreatBiTree(BiTree& T) {
	TEdatatype data;
    scanf("%c",&data);
	if (char == "#")  //"#"表示为空
		T = NULL;
	else {
		if (!T = (BiTree)malloc(sizeof(BiNode))){
			cout << "分配内存失败" << endl;
			exit(-1);
		}
        //利用前序存储,中序后序都一样
		T->_data = data;
		CreatBiTree(T->_Lchild);
		CreatBiTree(T->_Rchild);
	}
	return true;
}
3.2二叉树的销毁
//二叉树的销毁
bool DestroyBiTree(BiTree* T) {
	//T是指向BiTree T 的指针,也就是二级指针
	if (T) {
		if ((*T)->_Lchild)
            //别忘了引用噢(形参的改变不影响实参)
			DestroyBiTree(&(*T)->_Lchild);

		if ((*T)->_Rchild)
			DestroyBiTree(&(*T)->_Rchild);

		free(T);
		T = NULL;
	}
	return true;
}

#####3 .3二叉树的结点数

//还是用递归思路,简单来说就是从最后面一个二叉树开始计数,每次返回所二叉树的结点数在一起累加,最后+1是第一个结点
//二叉树的节点总数
int BiNodeCount(BiTree T) {

	if (T == NULL)
		return 0;
	return BiNodeCount(T->_Lchild) + BiNodeCount(T->_Rchild) + 1;
}
3.4二叉树的叶子结点数
//思路和二叉树的结点数大同小异,添加一项限制为叶子结点的特点左右孩子为空就行,
//二叉树的叶子节点个数
int BiNodeLeafCount(BiTree T) {

	if (T == NULL)
		return 0;
	if (T->_Lchild == NULL && T->_Rchild == NULL)
		return 1;
	return BiNodeLeafCount(T->_Lchild) + BiNodeLeafCount(T->_Rchild);
}
3.5二叉树的深度
//我们知道结点数为N的满二叉树(默认根结点的深度为1)深度为:log(N+1),下面就是任意二叉树的深度计算
//二叉树的深度
int BiNodeDepth(BiTree T) {
	if (T == NULL)
		return 0;
	int m = BiNodeDepth(T->_Lchild);
	int n = BiNodeDepth(T->_Rchild);
    
    //左右结点那个大,就在其上+1,就是当前的深度,在返回到上面依次累加
	if (m > n) {
		return m + 1;
	}
	else {
		return n + 1;
	}
}
3.6三种遍历:前序,中序,后序
//前序遍历
bool BiTreePreOrder(BiTree T) {
	if (T == NULL)
		return 0;
	cout << T->_data;
	BiTreePostOrder(T->_Lchild);
	BiTreePostOrder(T->_Rchild);
	return true;
}

//中序遍历
bool BiTreeInOrder(BiTree T) {
	if (T == NULL)
		return 0;
	BiTreePostOrder(T->_Lchild);
	cout << T->_data;
	BiTreePostOrder(T->_Rchild);
	return true;
}

//后序遍历
bool BiTreePostOrder(BiTree T) {
	if (T == NULL)
		return 0;
	BiTreePostOrder(T->_Lchild);
	BiTreePostOrder(T->_Rchild);
	cout << T->_data;
	return true;
}
3.7层次遍历和判断是否是完全二叉树

前面的还是比较基础,这两个需要利用到队列辅助实现所以说数据结构一定要学好,至少每个的代码呀,性质啥的都要做到心里有数

下面看到代码同学·

1.前期准备阶段:构造一个二叉链和链队

typedef char TEdatatype;

//二叉链
typedef struct BiNode {
	//数据
	TEdatatype _data;

	//左右孩子指针
	struct BiNode* _Lchild, * _Rchild;

}BiNode, * BiTree;


//typedef结点的指针,这就是我们队列的元素
typedef BiNode* QDataElem;

//我们使用的链队,顺序队有些麻烦
//链队的结点
typedef struct QNode {
	QDataElem _data;
	struct QNode* next;
}QNode, *pQueue;

//头尾指针
typedef struct LinkQueue {
	//头指针
	pQueue fornt;
	//尾指针
	pQueue rear;

}LinkQueue;

//初始化队列
bool InitQueue(LinkQueue& Q);

//销毁队列
bool DestroyQueue(LinkQueue& Q);

//判断队列为空
bool QueueEmpty(LinkQueue Q);

//入队
bool EnQueue(LinkQueue& Q, QDataElem e);

//出队
bool DeQueue(LinkQueue& Q, QDataElem& e);

2.开始利用链队,主要就是出队和入队判空这些性质

2.1队列的代码实现

//初始化队列
bool InitQueue(LinkQueue& Q) {
	//先创建一个队列节点,首尾指针都指向
	Q.fornt = Q.rear = (pQueue)malloc(sizeof(QNode));
	if (!Q.fornt) {
		exit(-1);
	}
	Q.fornt->next = NULL;
	return true;
}

//销毁队列
bool DestroyQueue(LinkQueue& Q) {
	pQueue p ;
    //类似链表的循环删除,从第一个开始
	while (Q.fornt) {
		p = Q.fornt->next;
		free(p);
		Q.fornt = p;
		//可以用尾指针代替p,
	}
	return true;
}

//判断队列为空
bool QueueEmpty(LinkQueue Q) {
	
	return Q.fornt = Q.rear = NULL;

}

//入队
bool EnQueue(LinkQueue& Q, QDataElem e) {
	//分配一个队列内存
	pQueue p = (pQueue)malloc(sizeof(QNode));
	if (!p) {
		exit(-1); //分配失败
	}
	//赋值给p结点,同时接上队列
	p->_data = e; p->next = NULL;
	Q.rear->next = p;
	//移动尾指针
	Q.rear = p;    //别忘了尾指针的移动
	return true;
}

//出队 e来存储出队的元素,当然你也可以按照你的喜好来作为返回值
bool DeQueue(LinkQueue& Q, QDataElem& e) {
	pQueue p=NULL;
	//为空
	if (!Q.rear) {
		cout << "队列为空";
		return false;
	}
	//一个数据
	if (Q.fornt = Q.rear) {
		e = Q.fornt->_data;
		free(Q.fornt);
		Q.fornt = Q.rear = NULL;  //释放内容之后,记得制空指针噢
		return true;
	}
    //普遍的多数据,链表学的好直接拿捏链队嘿嘿
	p = Q.fornt->next;
	e = Q.fornt->_data;
	free(Q.fornt);
	Q.fornt = p;    //别忘记了首指针的移动
	return true;
}

2.2层次遍历代码实现

//层次遍历需要队列
bool LevelOrder(BiTree T) {
    //管他先判空,在很多比赛中即使不会,也可以骗分嘿嘿
	if (T == NULL)
		return false;
    
	LinkQueue Q; BiTree TT;   //定义一个队列,定义一个二叉树(用来存出去的二叉树结点也就是队列元素)
	InitQueue(Q);     //初始化队列
	EnQueue(Q, T);    //根结点指针并入队列,,注意不是一个数据,是一个树进去了,为一串数据(数组)
	while (!QueueEmpty(Q)) {    //队列不为空,循环
		DeQueue(Q, TT);   //进去了根结点T,出结点T,存在TT,
		cout << TT->_data;      //打印TT,TT是头部元素
        //就是一层一层出了
		if(TT->_Lchild) EnQueue(Q, TT->_Lchild);    //有左孩子就出左孩子
		if (TT->_Rchild) EnQueue(Q, TT->_Rchild);   //有右孩子就出右孩子
	}
	return true;
}

2.3判断是否是完全二叉树


//是否是完全二叉数,利用一个巧妙的思维
bool BiTreeComplete(BiTree T) {
	if (T == NULL)
		return true;
	LinkQueue Q; BiTree TT;    //定义一个队列,定义一个二叉树
	InitQueue(Q);     //初始化队列
	EnQueue(Q, T);    //根结点指针并入队列,注意不是一个数据是一个树进去了,为一串数组
	while (!QueueEmpty(Q)) {    //队列不为空,循环
		DeQueue(Q, TT);   //进去了根结点T,出结点T,存在TT,
		if (TT == NULL) {
			break;
            //为什么二叉树中遇到了空就退出循环
            //完全二叉树一定是:前面有数据后面为空(ABCDEF#####)
            //非完全二叉树就是:(ABCDEF###G##H##)
            //所以我们只要判断后面为空部分中是不是有数据就行
		}
		if (TT->_Lchild) EnQueue(Q, TT->_Lchild);    //有左孩子就出左孩子
		if (TT->_Rchild) EnQueue(Q, TT->_Rchild);   //有右孩子就出右孩子
	}
     //完全二叉树一定是:前面有数据后面为空(ABCDEF#####)
    //非完全二叉树就是:(ABCDEF###G##H##)
    //后面为空的部分在来上面步骤,入队出队就行
	while (!QueueEmpty(Q)) {	
		DeQueue(Q, TT);  //和上面一样
		if (TT) {
			DestroyQueue(Q);  //记得销毁噢
			return false;
		}
	}
	DestroyQueue(Q);
	return true;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值