《数据结构(C语言版)第二版》第五章-树和二叉树(5.4-5.5.1)

5.4 二叉树的性质和存储结构

5.5 遍历二叉树和线索二叉树

5.5.1 遍历二叉树

先序、中序、后序遍历的递归算法

c 复制代码
//算法5.1 先序、中序、后序遍历的递归算法
#include <stdio.h>
#include  <stdlib.h>

typedef char TElemType;

typedef struct BiTNode
{
	TElemType data;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode, * BiTree;

void InitBiTree(BiTree& T);
void CreateBiTree(BiTree& T);
void preOrderTraverse(BiTree& T);
void InOrderTraverse(BiTree& T);
void posOrderTraverse(BiTree& T);

//ABC##DE#G##F###

int main()
{
	BiTree Tree = NULL;

	InitBiTree(Tree);
	printf("请输入要用二叉链表表示的字符序列: ");
	CreateBiTree(Tree);

	printf("\n二叉链表的先序序列为: ");
	preOrderTraverse(Tree);

	printf("\n二叉链表的中序序列为: ");
	InOrderTraverse(Tree);

	printf("\n二叉链表的后序序列为: ");
	posOrderTraverse(Tree);

	return 0;
}

//初始化二叉树
void InitBiTree(BiTree& T)
{
	T = NULL;
}

//按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T
//由于先序遍历的顺序是"根节点-左子树-右子树",因此仅有先序可以正确创建二叉树,当根结点为空时,令其整个二叉树为空,而不用管左右子树
void CreateBiTree(BiTree& T)
{
	TElemType ch = '\0';
	
	ch = getchar();  
	/* getchar从键盘获取且只能获取一个字符。
	  接收空格和制表符(空格或制表符会被算作一个正常字符读入一次),
	  不接收回车,遇到回车即认为本次输入结束。
	  但末尾输入的回车会被留在缓存流中,在下一次被getchar读取到(吃掉回车),并将该回车作为本次输入的结束。
	*/


	//scanf_s(" %c", &ch); //用scanf_s会将整个字符序列写进ch中,无法进行递归创建二叉树
	/*scanf_s在输入的末尾遇到空白符(空格符、回车符(\n)和制表符(\t)等) 时,都会认为本次输入结束。

	  对于参数%d:会忽略缓冲区开头的空白符(空格、回车、制表符等)(无论有几个),只从数字开始读取。
	  但对输入末尾的非数字字符,包括空白符,则可能进入无限循环程序,使得无法进行下一次输入;

	  对于参数%c:会直接读取缓冲区的第一个字符(无论这个字符是什么)。
	  所以一般需要在%c前面加一个空格,利用格式化的输入方式,使得遇到空格的scanf_s认为本次输入已结束,
	  直接等待下一次输入,而放弃缓冲区内的所有字符,来跳过上一次输入末尾的换行符。
	*/

	if (ch == '#')
	{
		T = NULL;
	}
	else
	{
		T = (BiTree)malloc(sizeof(BiTNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}


//先序遍历二叉树
void preOrderTraverse(BiTree& T)
{
	if (T)  //只有当T不为空时才访问它的成员
	{
		printf(" %c", T->data);
		preOrderTraverse(T->lchild);
		preOrderTraverse(T->rchild);
	}
}

//中序遍历二叉树
void InOrderTraverse(BiTree& T)
{
	if (T)
	{
		InOrderTraverse(T->lchild);
		printf(" %c", T->data);
		InOrderTraverse(T->rchild);
	}
}

//后序遍历二叉树
void posOrderTraverse(BiTree& T)
{
	if (T)
	{
		posOrderTraverse(T->lchild);
		posOrderTraverse(T->rchild);
		printf(" %c", T->data);
	}
}


先序、中序、后序遍历的非递归算法

c 复制代码
//先序、中序、后序遍历二叉树的非递归算法

#include <stdio.h>
#include  <stdlib.h>

typedef char TElemType;

typedef struct BiTNode
{
	TElemType data;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode, * BiTree;

//链栈的数据结构
typedef struct StackNode
{
	BiTree TNodeptr;
	struct StackNode* next;
}StackNode, * LinkStack;

void InitStack(LinkStack& S);
void Push(LinkStack& S, BiTree p);
BiTree Pop(LinkStack& S);
BiTree GetTop(LinkStack& S);
int EmptyStack(LinkStack& S);
void InitBiTree(BiTree& T);
void CreateBiTree(BiTree& T);
void preOrderTraverse(BiTree& T);
void InOrderTraverse(BiTree& T);
void posOrderTraverse(BiTree& T);

/* 按先序次序输入二叉树中结点的值:(输入的结尾一定是两个#号)
	ABC##DE#G##F###
	-*a##b##c## 
	ABD##E##C##	*/

int main()
{
	BiTree Tree = NULL;
	InitBiTree(Tree);

	char choice = '\0';

	while (1)
	{
		printf("请输入要用二叉链表表示的字符先序序列: ");
		CreateBiTree(Tree);

		printf("\n二叉链表的先序序列为: ");
		preOrderTraverse(Tree);

		printf("\n二叉链表的中序序列为: ");
		InOrderTraverse(Tree);

		printf("\n二叉链表的后序序列为: ");
		posOrderTraverse(Tree);


		printf("\n是否继续?(y/n):");
		scanf_s(" %c", &choice);
		getchar();
		if (choice != 'y' && choice != 'Y')
		{
			break;
		}

		printf("\n\n");
	}

	return 0;
}

//初始化栈
void InitStack(LinkStack& S)
{
	S = NULL;
}

//元素进栈
void Push(LinkStack& S, BiTree p)
{
	struct StackNode* r = NULL;
	r = (struct StackNode*)malloc(sizeof(struct StackNode));

	if (!r)
	{
		printf("创建新结点时,内存分配失败。");
		return;
	}

	r->TNodeptr = p;
	r->next = S;
	S = r;
}

//栈顶元素出栈
BiTree Pop(LinkStack& S)
{
	if (!S)
	{
		printf("弹出栈顶元素时,栈不存在。");
		return NULL;
	}

	struct StackNode* r = S;
	BiTree a = S->TNodeptr;
	S = S->next;
	free(r);
	return a;
}

//获取栈顶元素
BiTree GetTop(LinkStack& S)
{
	if (!S)
	{
		printf("获取栈顶元素时,栈不存在。");
		return NULL;
	}

	return S->TNodeptr;
}

//判断栈是否为空
int EmptyStack(LinkStack& S)
{
	if (!S)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}


//初始化二叉树
void InitBiTree(BiTree& T)
{
	T = NULL;
}

//按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T
void CreateBiTree(BiTree& T)
{
	TElemType ch = '\0';

	ch = getchar();

	if (ch == '#')
	{
		T = NULL;
	}
	else
	{
		T = (BiTree)malloc(sizeof(BiTNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}


//先序遍历二叉树的非递归算法
void preOrderTraverse(BiTree& T)
{
	LinkStack S = NULL;
	InitStack(S);

	BiTree p = T; //初始化指向根结点的p为二叉树的根结点T

	while (p || !EmptyStack(S))
	{
		if (p)
		{
			printf("%c", p->data);
			Push(S, p);
			p = p->lchild;
		}
		else
		{
			p = Pop(S);
			p = p->rchild;
		}
	}
}


//中序遍历二叉树的非递归算法
void InOrderTraverse(BiTree& T)
{
	LinkStack S = NULL;
	InitStack(S);

	BiTree p = T; //初始化指向根结点的p为二叉树的根结点T
	BiTree q = (BiTree)malloc(sizeof(BiTNode));  //可以不设置q,程序里的q直接改为p
	if (!q)
	{
		printf("非递归算法中序遍历二叉树时,用来存放栈顶弹出的指针元素的q内存分配失败。");
		return;
	}

	while (p || !EmptyStack(S))
	{
		if (p)
		{
			Push(S, p);
			p = p->lchild;
		}
		else
		{
			q = Pop(S);
			printf("%c", q->data);
			p = q->rchild;
		}
	}
}

//后序遍历二叉树的非递归算法
void posOrderTraverse(BiTree& T)
{  
	LinkStack S = NULL;
	InitStack(S);

	BiTree p = T;
	BiTree r = NULL;// r标记最近访问过的结点

	while (p != NULL || !EmptyStack(S)) 
	{
		if (p != NULL) 
		{
			Push(S, p);  // 一直向左走,左孩子入栈
			p = p->lchild;
		}
		else  //①只有左孩子为空时(即无法进入第一层if),才会进入else语句,利用栈进行右子树及根结点本身的判断与访问,符合后序遍历的规定
		{
			p = GetTop(S);  //获取s的栈顶元素赋值给p,GetTop(s,p)意思就是判断栈顶元素的情况

			if (p->rchild && p->rchild != r) //②若右孩子存在且未被访问,则先进行右孩子的后序遍历,再进行根结点本身的访问,符合后序遍历的规定
			{			
				p = p->rchild;  // 就让右孩子
				Push(S, p);    //入栈
				p = p->lchild;  // 让右孩子向左
				//上面三句意思就是右孩子的左孩子非空的话就重新进入while循环,入栈,并一直向左走,非空的话就一直入栈
			}
			else //③左子树和右子树都后序遍历完了,最后进行根结点本身的访问。
			{
				p = Pop(S); // 右孩子为空或未被访问过,就出栈
				printf("%c", p->data);
				/* 根结点p的data值已输出,根据后序遍历的过程,以结点p为根结点的二叉树的后续遍历已经完成。
					④接下来应该进行以根结点p为子树的二叉树(假设根结点是x)的后序遍历(所以此步将p置空,进而可以进入第一层else,获取根结点x的信息):
					当p是x的左子树根结点时,则应该进行x的右子树(假设根结点是y)的遍历(对应上面第二层if判断);
					当p是x的右子树根结点时,则应该进行x的输出。(在上面第二层if判断中,x的右子树即p已经被访问过,所以还会进入该else语句中,弹出x结点)
					若p不是子树的根结点,那么就是整个二叉树的根结点(有且仅有这一种情况),说明整个二叉树后序遍历完成了。 */

				r = p;  // r标记最近访问结点

				p = NULL;  // p置空
			}
		}
	}
}

二叉树:后序遍历非递归算法------ 花间半盘棋

c 复制代码
//按先序次序输入二叉树中结点的值:(输入的结尾一定是两个#号):
//ABD##E##C##

//后序遍历二叉树的非递归算法
void posOrderTraverse(BiTree& T)
{  
	LinkStack S = NULL;
	InitStack(S);

	BiTree p = T;
	BiTree r = NULL;// r标记最近访问过的结点

	while (p != NULL || !EmptyStack(S)) 
	{
		if (p != NULL) 
		{
			printf("\n第一层if中:p = %c\n", p->data);

			Push(S, p);  // 一直向左走,左孩子入栈
			p = p->lchild;
			
			if (p)
			{
				printf("第一层if中:p = %c\n", p->data);
			}
			else
			{
				printf("第一层if中:p = %c\n", '#');
			}
		}
		else  //①只有左孩子为空时(即无法进入第一层if),才会进入else语句,利用栈进行右子树及根结点本身的判断与访问,符合后序遍历的规定
		{
			p = GetTop(S);  //获取s的栈顶元素赋值给p,GetTop(s,p)意思就是判断栈顶元素的情况
			printf("第一层else中:p = %c\n", p->data);

			if (p->rchild && p->rchild != r) //②若右孩子存在且未被访问,则先进行右孩子的后序遍历,再进行根结点本身的访问,符合后序遍历的规定
			{			
				printf("第二层if中:p->rchild = %c\n", p->rchild->data);

				p = p->rchild;  // 就让右孩子
				Push(S, p);    //入栈
				p = p->lchild;  // 让右孩子向左
				//上面三句意思就是右孩子的左孩子非空的话就重新进入while循环,入栈,并一直向左走,非空的话就一直入栈
				
				if (p)
				{
					printf("第二层if中:p = %c\n", p->data);
				}
				else
				{
					printf("第二层if中:p = %c\n", '#');
				}
			}
			else //③左子树和右子树都后序遍历完了,最后进行根结点本身的访问。
			{
				p = Pop(S); // 右孩子为空或未被访问过,就出栈
				printf("输出的p为 : %c\n", p->data);
				/* 根结点p的data值已输出,根据后序遍历的过程,以结点p为根结点的二叉树的后续遍历已经完成。
					④接下来应该进行以根结点p为子树的二叉树(假设根结点是x)的后序遍历(所以此步将p置空,进而可以进入第一层else,获取根结点x的信息):
					当p是x的左子树根结点时,则应该进行x的右子树(假设根结点是y)的遍历(对应上面第二层if判断);
					当p是x的右子树根结点时,则应该进行x的输出。(在上面第二层if判断中,x的右子树即p已经被访问过,所以还会进入该else语句中,弹出x结点)
					若p不是子树的根结点,那么就是整个二叉树的根结点(有且仅有这一种情况),说明整个二叉树后序遍历完成了。 */

				r = p;  // r标记最近访问结点
				printf("第二层else中:r = %c\n", r->data);

				p = NULL;  // p置空
			}
		}
	}
}

层次遍历的非递归算法

c 复制代码
//层次遍历的非递归算法

#include <stdio.h>
#include <stdlib.h>

typedef char TElemType;

//二叉链表
typedef struct BiTNode
{
	TElemType data;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode,*BiTree;

//链队
typedef struct QueueNode
{
	BiTree TNodeptr;
	struct QueueNode* next;
}QueueNode, * QNodeptr;

typedef struct
{
	QNodeptr front;
	QNodeptr rear;
}LinkQueue;

void InitQueue(LinkQueue& Q);
void EnQueue(LinkQueue& Q, BiTree p);
BiTree DeQueue(LinkQueue& Q);
int EmptyQueue(LinkQueue& Q);
void InitBiTree(BiTree& T);
void CreateBiTree(BiTree& T);
void LevelOrderTraverse(BiTree& T);

int main()
{
	BiTree Tree = NULL;
	InitBiTree(Tree);

	char choice = '\0';

	while (1)
	{
		printf("请输入要用二叉链表表示的字符先序序列: ");
		CreateBiTree(Tree);

		printf("二叉链表的层次遍历序列为: ");
		LevelOrderTraverse(Tree);

		printf("\n是否继续?(y/n):");
		scanf_s(" %c", &choice);
		getchar();
		if (choice != 'y' && choice != 'Y')
		{
			break;
		}

		printf("\n\n");
	}

	return 0;
}

//初始化链队(有头结点,需要分配内存)
void InitQueue(LinkQueue& Q)
{
	Q.front = (QNodeptr)malloc(sizeof(QueueNode));
	if (!Q.front)
	{
		printf("初始化链队时,内存分配失败。\n");
		return;
	}

	Q.rear = Q.front;
	Q.front->next = NULL;
}

//进队
void EnQueue(LinkQueue& Q, BiTree p)
{
	QNodeptr r = (QNodeptr)malloc(sizeof(QueueNode));
	
	if (!r)
	{
		printf("元素进队时,新结点内存分配失败。\n");
		return;
	}

	r->TNodeptr = p;
	r->next = NULL;

	Q.rear->next = r;
	Q.rear = r;
}

//出队
BiTree DeQueue(LinkQueue& Q)
{
	if (Q.front == Q.rear)
	{
		printf("队头元素出队时,链队为空。\n");
		return NULL;
	}

	QNodeptr r = Q.front->next;
	BiTree e = r->TNodeptr;
	Q.front->next = r->next;

	if (Q.rear == r)
	{
		Q.rear = Q.front;
	}

	free(r);
	return e;
}

//判空
int EmptyQueue(LinkQueue& Q)
{
	if (Q.front == Q.rear)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

//初始化二叉树
void InitBiTree(BiTree& T)
{
	T = NULL;
}

//按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T
void CreateBiTree(BiTree& T)
{
	TElemType ch = '\0';

	ch = getchar();

	if (ch == '#')
	{
		T = NULL;
	}
	else
	{
		T = (BiTree)malloc(sizeof(BiTNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}


//层次遍历二叉树
void LevelOrderTraverse(BiTree& T)
{
	LinkQueue Q = { NULL,NULL };
	InitQueue(Q);

	BiTree p = T;

	if (p)
	{
		EnQueue(Q,p);

		while (!EmptyQueue(Q))
		{
			p = DeQueue(Q);
			printf("%c", p->data);

			if (p->lchild)
			{
				EnQueue(Q, p->lchild);
			}

			if (p->rchild)
			{
				EnQueue(Q, p->rchild);
			}
		}

	}
}

复制二叉树、计算二叉树深度、统计二叉树中结点个数的递归算法

c 复制代码
//复制二叉树、计算二叉树深度、统计二叉树中结点个数的递归算法

#include <stdio.h>
#include  <stdlib.h>

typedef char TElemType;

typedef struct BiTNode
{
	TElemType data;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode, * BiTree;

void InitBiTree(BiTree& T);
void CreateBiTree(BiTree& T);
void preOrderTraverse(BiTree& T);
void InOrderTraverse(BiTree& T);
void posOrderTraverse(BiTree& T);
BiTree Copy(BiTree& T);
int Depth(BiTree& T);
int NodeCount(BiTree T);

/* 按先序次序输入二叉树中结点的值:(输入的结尾一定是两个#号)
	ABC##DE#G##F###
	-*a##b##c##
	ABD##E##C##	*/

int main()
{
	BiTree Tree = NULL;
	BiTree NewTree = NULL;

	InitBiTree(Tree);
	printf("请输入要用二叉链表表示的字符序列: ");
	CreateBiTree(Tree);

	printf("\n二叉链表的先序序列为: ");
	preOrderTraverse(Tree);

	printf("\n二叉链表的中序序列为: ");
	InOrderTraverse(Tree);

	printf("\n二叉链表的后序序列为: ");
	posOrderTraverse(Tree);

	printf("\n该二叉链表的深度为:%d", Depth(Tree));
	printf("\n该二叉链表的结点个数为:%d", NodeCount(Tree));


	NewTree = Copy(Tree);

	printf("\n\n复制该二叉链表后得到新序列的先序序列为: ");
	preOrderTraverse(NewTree);

	printf("\n复制该二叉链表后得到新序列的中序序列为: ");
	InOrderTraverse(NewTree);

	printf("\n复制该二叉链表后得到新序列的后序序列为: ");
	posOrderTraverse(NewTree);

	printf("\n新序列的深度为:%d", Depth(NewTree));
	printf("\n新序列的结点个数为:%d", NodeCount(NewTree));

	return 0;
}

//初始化二叉树
void InitBiTree(BiTree& T)
{
	T = NULL;
}

//按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T
void CreateBiTree(BiTree& T)
{
	TElemType ch = '\0';

	ch = getchar();

	if (ch == '#')
	{
		T = NULL;
	}
	else
	{
		T = (BiTree)malloc(sizeof(BiTNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}


//先序遍历二叉树
void preOrderTraverse(BiTree& T)
{
	if (T)  //只有当T不为空时才访问它的成员
	{
		printf(" %c", T->data);
		preOrderTraverse(T->lchild);
		preOrderTraverse(T->rchild);
	}
}

//中序遍历二叉树
void InOrderTraverse(BiTree& T)
{
	if (T)
	{
		InOrderTraverse(T->lchild);
		printf(" %c", T->data);
		InOrderTraverse(T->rchild);
	}
}

//后序遍历二叉树
void posOrderTraverse(BiTree& T)
{
	if (T)
	{
		posOrderTraverse(T->lchild);
		posOrderTraverse(T->rchild);
		printf(" %c", T->data);
	}
}

//算法5.4 复制二叉树的递归算法
BiTree Copy(BiTree& T)
{
	BiTree NewT = NULL;

	if (T == NULL)
	{
		NewT = NULL;
	}
	else
	{
		NewT = (BiTree)malloc(sizeof(BiTNode));
		NewT->data = T->data;
		NewT->lchild = Copy(T->lchild);
		NewT->rchild = Copy(T->rchild);
	}

	return NewT;
}

//算法5.5 计算二叉树深度的递归算法
int Depth(BiTree &T)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		int m = Depth(T->lchild);  
		int n = Depth(T->rchild);
		//不能从一开始就定义m、n两个变量。否则不管初始化为多少,输出的深度总比实际值小1

		if (m > n)
		{
			return m + 1;
		}
		else
		{
			return n + 1;
		}
	}
}

//算法5.6 统计二叉树中结点个数的递归算法
int NodeCount(BiTree T)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		return NodeCount(T->lchild) + NodeCount(T->rchild) + 1;
	}
}
c 复制代码
//算法5.4 复制二叉树的递归算法

BiTree Copy(BiTree& T)
{
	BiTree NewT = NULL;

	if (T == NULL)
	{
		NewT = NULL;
	}
	else
	{
		NewT = (BiTree)malloc(sizeof(BiTNode));

		NewT->data = T->data;
		printf("\nT = NewT = %c\n", NewT->data);

		if (T->lchild)
		{
			printf("T->lchild = %c\n", T->lchild->data);
		}
		else
		{
			printf("T->lchild = %c\n", '#');
		}

		NewT->lchild = Copy(T->lchild);

		if (NewT->lchild)
		{
			printf("\nNewT->lchild = %c\n", NewT->lchild->data);
		}
		else
		{
			printf("\nNewT->lchild = %c\n", '#');
		}


		if (T->rchild)
		{
			printf("\nT->rchild = %c\n", T->rchild->data);
		}
		else
		{
			printf("\nT->rchild = %c\n", '#');
		}

		NewT->rchild = Copy(T->rchild);

		if (NewT->rchild)
		{
			printf("\nNewT->rchild = %c\n", NewT->rchild->data);
		}
		else
		{
			printf("\nNewT->rchild = %c\n", '#');
		}
	}
	printf("\n复制二叉链表后得到新序列的先序序列为: ");
	preOrderTraverse(NewT);

	return NewT;
}


//先序遍历二叉树
void preOrderTraverse(BiTree& T)
{
	if (T)  //只有当T不为空时才访问它的成员
	{
		printf(" %c", T->data);
		preOrderTraverse(T->lchild);
		preOrderTraverse(T->rchild);
	}
	else
	{
		printf(" %c", '#');
	}
}



c 复制代码
//算法5.5 计算二叉树深度的递归算法

int Depth(BiTree &T)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		printf("\nT = %c\n", T->data);

		if (T->lchild)
		{
			printf("T->lchild = %c\n", T->lchild->data);
		}
		else
		{
			printf("T->lchild = %c\n", '#');
		}

		int m = Depth(T->lchild);  
		printf("m = %d\n", m);

		if (T->rchild)
		{
			printf("T->rchild = %c\n", T->rchild->data);
		}
		else
		{
			printf("T->rchild = %c\n", '#');
		}

		int n = Depth(T->rchild);
		printf("n = %d\n", n);
		//不能从一开始就定义m、n两个变量。否则不管初始化为多少,输出的深度总比实际值小1

		if (m > n)
		{
			return m + 1;
		}
		else
		{
			return n + 1;
		}
	}
}


c 复制代码
//算法5.6 统计二叉树中结点个数的递归算法

int NodeCount(BiTree T)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		printf("\nT = %c\n", T->data);

		if (T->lchild)
		{
			printf("T->lchild = %c\n", T->lchild->data);
		}
		else
		{
			printf("T->lchild = %c\n", '#');
		}

		int a = NodeCount(T->lchild);
		printf("a = %d\n", a);

		if (T->rchild)
		{
			printf("T->rchild = %c\n", T->rchild->data);
		}
		else
		{
			printf("T->rchild = %c\n", '#');
		}

		int b = NodeCount(T->rchild);
		printf("b = %d\n", b);

		return  a + b + 1;
	}
}


复制二叉树、计算二叉树深度、统计二叉树中结点个数的非递归算法

统计二叉树中叶结点(度为 0) 的个数、度为1的结点个数、度为2的结点个数、计算二叉树第k层的结点个数、查找二叉树中的目标值的递归算法

数据结构 统计二叉树中度为0,1和2的结点个数------ 1900_

二叉树的基本操作(如何计算二叉树的结点个数,二叉树的高度) ------ 初阶牛

c 复制代码
//统计二叉树中叶结点(度为 0) 的个数,度为1的结点个数和度为2的结点个数的递归算法
//计算二叉树第k层的结点个数的递归算法
//查找二叉树中的目标值的递归算法

#include <stdio.h>
#include  <stdlib.h>

typedef char TElemType;

typedef struct BiTNode
{
	TElemType data;
	struct BiTNode* lchild;
	struct BiTNode* rchild;
}BiTNode, * BiTree;

void InitBiTree(BiTree& T);
void CreateBiTree(BiTree& T);
void preOrderTraverse(BiTree& T);
void InOrderTraverse(BiTree& T);
void posOrderTraverse(BiTree& T);
int LeafNodeCount(BiTree T);
int NodeCount_1(BiTree T);
int NodeCount_2(BiTree T);
int NodeCount_kLevel(BiTree T, int k); //计算二叉树第k层的结点个数的递归算法
BiTree FindNode(BiTree T, TElemType e); //查找二叉树中的目标值的递归算法

/* 按先序次序输入二叉树中结点的值:(输入的结尾一定是两个#号)
	ABC##DE#G##F###
	-*a##b##c##
	ABD##E##C##	*/

int main()
{
	BiTree Tree = NULL;

	InitBiTree(Tree);
	printf("请输入要用二叉链表表示的字符序列: ");
	CreateBiTree(Tree);

	printf("\n二叉链表的先序序列为: ");
	preOrderTraverse(Tree);

	printf("\n二叉链表的中序序列为: ");
	InOrderTraverse(Tree);

	printf("\n二叉链表的后序序列为: ");
	posOrderTraverse(Tree);

	printf("\n\n该二叉链表的叶子结点是:");
	printf("\n该二叉链表叶子节点的个数为:%d", LeafNodeCount(Tree));

	printf("\n\n该二叉链表度为1的结点是:");
	printf("\n该二叉链表度为1的结点个数为:%d", NodeCount_1(Tree));

	printf("\n\n该二叉链表度为2的结点是:");
	printf("\n该二叉链表度为2的结点个数为:%d", NodeCount_2(Tree));

	printf("\n\n该二叉链表第%d层的结点是:",3);
	printf("\n该二叉链表第%d层的结点个数为:%d", 3, NodeCount_kLevel(Tree,3));


	printf("\n\n%c结点在该二叉链表中的位置为:%c", 'G', (FindNode(Tree, 'G'))->data);

	return 0;
}

//初始化二叉树
void InitBiTree(BiTree& T)
{
	T = NULL;
}

//按先序次序输入二叉树中结点的值(一个字符),创建二叉链表表示的二叉树T
void CreateBiTree(BiTree& T)
{
	TElemType ch = '\0';

	ch = getchar();

	if (ch == '#')
	{
		T = NULL;
	}
	else
	{
		T = (BiTree)malloc(sizeof(BiTNode));
		T->data = ch;
		CreateBiTree(T->lchild);
		CreateBiTree(T->rchild);
	}
}


//先序遍历二叉树
void preOrderTraverse(BiTree& T)
{
	if (T)  //只有当T不为空时才访问它的成员
	{
		printf(" %c", T->data);
		preOrderTraverse(T->lchild);
		preOrderTraverse(T->rchild);
	}
}

//中序遍历二叉树
void InOrderTraverse(BiTree& T)
{
	if (T)
	{
		InOrderTraverse(T->lchild);
		printf(" %c", T->data);
		InOrderTraverse(T->rchild);
	}
}

//后序遍历二叉树
void posOrderTraverse(BiTree& T)
{
	if (T)
	{
		posOrderTraverse(T->lchild);
		posOrderTraverse(T->rchild);
		printf(" %c", T->data);
	}
}


//统计二叉树中叶结点(度为 0) 的个数的递归算法
int LeafNodeCount(BiTree T)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		if (T->lchild == NULL && T->rchild == NULL) //判断是否是叶子结点
		{
			printf("%c ", T->data);
			return 1;
		}
		else
		{
			int left = LeafNodeCount(T->lchild); //统计左子树中叶子结点的个数
			int right = LeafNodeCount(T->rchild); //统计右子树中叶子结点的个数
			return left + right;
		}
	}
}

//统计二叉树中度为1的结点个数的递归算法
int NodeCount_1(BiTree T)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		//判断结点的度是否为1
		if ((T->lchild == NULL && T->rchild != NULL) || (T->lchild != NULL && T->rchild == NULL)) 
		{
			printf("%c ", T->data);
			int left = NodeCount_1(T->lchild); //统计根结点T左子树中度为1的结点个数
			int right = NodeCount_1(T->rchild); //统计根结点T右子树中度为1的结点个数
			return 1 + left + right;  //前面加1是因为该根结点T本身是度为1的结点
		}
		else  //T的左右子树都不为空或者都为空,T均不是度为1的结点,所以不加1
		{
			int left = NodeCount_1(T->lchild); //统计根结点T左子树中度为1的结点个数
			int right = NodeCount_1(T->rchild); //统计根结点T右子树中度为1的结点个数
			return left + right;
		}
	}
}

//统计二叉树中度为2的结点个数的递归算法
int NodeCount_2(BiTree T)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		//判断结点的度是否为2
		if (T->lchild != NULL && T->rchild != NULL)
		{
			printf("%c ", T->data);
			int left = NodeCount_2(T->lchild); //统计根结点T左子树中度为2的结点个数
			int right = NodeCount_2(T->rchild); //统计根结点T右子树中度为2的结点个数
			return 1 + left + right;  //前面加1是因为该根结点T本身是度为2的结点
		}
		else  //T的左右子树有一个为空,或者均为空,T均不是度为2的结点,所以不加1
		{
			int left = NodeCount_2(T->lchild); //统计根结点T左子树中度为2的结点个数
			int right = NodeCount_2(T->rchild); //统计根结点T右子树中度为2的结点个数
			return left + right;
		}
	}
}

//计算二叉树第k层的结点个数的递归算法【不超过2^(k-1)个】

/* 当k大于1时,递归的思路是:
  以T所在的层次为第一层,其第k层的结点个数  
  = 以T的左子树所在的层次为第一层(原来在第二层),其第k-1层的结点个数 NodeCount_kLevel(T->lchild, k-1) 
     + 以T的右子树所在的层次为第一层(原来在第二层),其第k-1层的结点个数 NodeCount_kLevel(T->rchild, k-1)
 
  直到原来第k层成为第一层,其就成为了根结点,则第一层的结点个数一定为1 ,再依次返回递归的结果*/
  
int NodeCount_kLevel(BiTree T, int k)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		if (k == 1)
		{
			printf("%c ", T->data);
			return 1;
		}
		else
		{
			int left = NodeCount_kLevel(T->lchild, k - 1);
			int right = NodeCount_kLevel(T->rchild, k - 1);
			return left + right;
		}
	}
}

//查找二叉树中的目标值的递归算法
BiTree FindNode(BiTree T,TElemType e)
{
	if (T == NULL)
	{
		return NULL;
	}
	else if(T->data == e) //先判断根节点
	{
		return T;
	}
	else
	{
		//先搜索左子树
		BiTree left = FindNode(T->lchild, e);
		if (left) 
		{
			return left;  //如果左子树找到了就返回左子树找到的结点
		}

		//再搜索右子树
		BiTree right = FindNode(T->rchild, e);
		if (right)
		{
			return right;  //如果右子树找到了就返回右子树找到的结点
		}

		return NULL;  //左右子树都没找到
	}
}
c 复制代码
//计算二叉树第k层的结点个数的递归算法【不超过2^(k-1)个】

/* 当k大于1时,递归的思路是:
  以T所在的层次为第一层,其第k层的结点个数  
  = 以T的左子树所在的层次为第一层(原来在第二层),其第k-1层的结点个数 NodeCount_kLevel(T->lchild, k-1) 
     + 以T的右子树所在的层次为第一层(原来在第二层),其第k-1层的结点个数 NodeCount_kLevel(T->rchild, k-1)
 
  直到原来第k层成为第一层,其就成为了根结点,则第一层的结点个数一定为1 ,再依次返回递归的结果*/

int NodeCount_kLevel(BiTree T, int k)
{
	if (T == NULL)
	{
		return 0;
	}
	else
	{
		printf("\nT = %c\n", T->data);

		if (k == 1)
		{
			return 1;
		}
		else
		{
			if (T->lchild)
			{
				printf("T->lchild = %c\n", T->lchild->data);
			}
			else
			{
				printf("T->lchild = %c\n", '#');
			}

			printf("k = %d\n", k);

			int left = NodeCount_kLevel(T->lchild, k-1);
			
			printf("left = %d\n", left);

			if (T->rchild)
			{
				printf("T->rchild = %c\n", T->rchild->data);
			}
			else
			{
				printf("T->rchild = %c\n", '#');
			}

			printf("k = %d\n", k);

			int right = NodeCount_kLevel(T->rchild, k-1);

			printf("right = %d\n", right);

			return left + right;
		}
	}
}

统计二叉树中叶结点(度为 0) 的个数、度为1的结点个数、度为2的结点个数、计算二叉树第k层的结点个数、查找二叉树中的目标值的非递归算法

相关推荐
waicsdn_haha8 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
嵌入式科普9 分钟前
十三、从0开始卷出一个新项目之瑞萨RZN2L串口DMA接收不定长
c语言·stm32·瑞萨·e2studio·rzn2l
_WndProc10 分钟前
C++ 日志输出
开发语言·c++·算法
薄荷故人_12 分钟前
从零开始的C++之旅——红黑树及其实现
数据结构·c++
qq_4335545419 分钟前
C++ 面向对象编程:+号运算符重载,左移运算符重载
开发语言·c++
努力学习编程的伍大侠24 分钟前
基础排序算法
数据结构·c++·算法
数据小爬虫@38 分钟前
如何高效利用Python爬虫按关键字搜索苏宁商品
开发语言·爬虫·python
ZJ_.40 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
Narutolxy1 小时前
深入探讨 Go 中的高级表单验证与翻译:Gin 与 Validator 的实践之道20241223
开发语言·golang·gin
XiaoLeisj1 小时前
【递归,搜索与回溯算法 & 综合练习】深入理解暴搜决策树:递归,搜索与回溯算法综合小专题(二)
数据结构·算法·leetcode·决策树·深度优先·剪枝