二叉树基础练习

##binarytree.h

#include<stdio.h>
#include<windows.h>
#include<assert.h>

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	struct BinaryTreeNode* _left;   //左孩子
	struct BinaryTreeNode* _right;  //右孩子
	BTDataType _data;               //数据域
}BTNode;//树的每个节点
#include"stack.h"
#include"queue.h"



BTNode *BuyNewNode(BTDataType x)//创建新节点
{
	BTNode *newnode = (BTNode *)malloc(sizeof(BTNode));
	assert(newnode);
	newnode->_data = x;
	newnode->_left = NULL;
	newnode->_right = NULL;
	return newnode;
}
BTNode *BinaryTreeCreateByPrev(int *a, int *index, int invalid)//先序创建二叉树
{
	//思路:
	//从数组头开始读取数据,遇到合法值,创建新节点,紧接着递归的创建左孩子和右孩子,V L R
	//遇到非法值时直接return NULL,创建完左右孩子return 当前节点的地址
	assert((*index) >= 0);
	if (a[*index] == invalid)
	{
		return NULL;
	}

	//到这一步时,可以判断数组的当前位置值为合法的,开始创建新节点
	BTNode *root = BuyNewNode(a[*index]);
	++(*index);//数组下标后移
	root->_left = BinaryTreeCreateByPrev(a, index, invalid);//递归:创建左孩子
	++(*index);//数组下标后移
	root->_right = BinaryTreeCreateByPrev(a, index, invalid);//递归:创建右孩子

															 //左右孩子都创建好,或者因非法return  NULL
															 //返回上层递归
	return root;

}
void BTreePrevOrder(BTNode *root)//先序,递归遍历二叉树   V L R
{
	//子问题:每个节点的左右孩子都要保证以R L T方式遍历
	//递归出口:抵达叶子节点,在向下遍历为空时

	if (root == NULL)
	{
		return;
	}
	//到这里说明还该处有节点,依照 V L R依次遍历,每个节点都是如此
	printf("%2d", root->_data);
	BTreePrevOrder(root->_left);
	BTreePrevOrder(root->_right);
}


void BTreeInOrder(BTNode* root)//中序遍历二叉树
{
	//子问题:每个节点的左右孩子必须按照L V R顺序遍历
	//递归出口:抵达叶子节点,在向下遍历为空时

	if (root == NULL)
	{
		return;
	}
	BTreeInOrder(root->_left);
	printf("%2d", root->_data);
	BTreeInOrder(root->_right);
}

void BTreePostOrder(BTNode* root)//后序遍历二叉树
{
	//子问题:每个节点的左右孩子都必须按照 L R V顺序遍历
	//递归出口:抵达叶子节点,在向下遍历为空时
	if (root == NULL)
	{
		return;
	}
	BTreePostOrder(root->_left);
	BTreePostOrder(root->_right);
	printf("%2d", root->_data);

}
size_t BTreeSize(BTNode* root)//二叉树的总结点数
{
	//子问题:一个树的节点个数都可以分解成 1 + 其左子树的节点个数 + 其右节点的节点个数
	if (root == NULL)
	{
		return 0;
	}

	return (1 + BTreeSize(root->_left) + BTreeSize(root->_right));
}
size_t BTreeLeafSize(BTNode* root)//二叉树的叶子节点数
{

	//如果树为空,返回0;
	//如果该节点为叶子节点,返回1
	//子问题:如果该节点不是叶子节点(有左右子树),返回其左子树的叶子节点个数 + 右子树节点个数
	if (root == NULL)
	{
		return 0;
	}
	if (root->_left == NULL&&root->_right == NULL)
	{
		return 1;
	}
	return BTreeLeafSize(root->_left) + BTreeLeafSize(root->_right);
}
size_t BTreeKLevelSize(BTNode* root, size_t k)//二叉树第k层节点数
{
	//子问题:如果当前层不是我们要查的,则k--,
	//且改为查其左子树的第k层的节点数+其右节点的第k层的节点数
	//递归出口:k==1,此时一定是我们要查的层数,返回当前节点数
	assert(k);//k至少为1
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	k--;
	return BTreeKLevelSize(root->_left, k) + BTreeKLevelSize(root->_right, k);
}
size_t BTreeDepth(BTNode* root)//二叉树的深度
{
	//子问题:从根结点开始,如果根节点有左右子树,那么他的深度为1+(左子树深度||右子树深度(取大值))
	//递归出口:如果当前节点已经是最深的节点,则返回0;
	if (root == NULL)
	{
		return 0;
	}
	size_t left = BTreeDepth(root->_left);
	size_t right = BTreeDepth(root->_right);
	return 1 + (left > right ? left : right);
}

void BTreeLevelOrder(BTNode* root)//广度遍历二叉树
{
	//思路:层序遍历需要借助一个队列完成,当根节点不为空时,将根节点指针入队,为空直接返回。
	//接着进入循环:如果队头节点有左节点或者右节点,则将他们的指针入队,然后对队头元素指针出队并打印,
	//直至队列为空
	Queue q;
	QueueInit(&q);
	if (root == NULL)
	{
		return;
	}
	QueuePush(&q, root);
	while (QueueEmpty(&q))
	{
		BTNode *front = QueueFront(&q);
		if (front->_left != NULL)
		{
			QueuePush(&q, front->_left);
		}
		if (front->_right != NULL)
		{
			QueuePush(&q, front->_right);
		}
		printf("%2d", front->_data);
		QueuePop(&q);
		free(front);
	}


}
BTNode* BTreeFind(BTNode* root, BTDataType x)//二叉树的查找
{
	//思路:若树为空树,则return NULL
	//		如果找到,return x的指针
	//		递归遍历左子树和右子树继续找
	if (root == NULL)
	{
		return NULL;
	}
	if (root->_data == x)
	{
		return root;
	}
	BTNode *ret = NULL;
	if (root->_left)
	{
		ret = BTreeFind(root->_left, x);
		if (ret)
		{
			return ret;
		}
	}

	if (root->_right)
	{
		ret = BTreeFind(root->_right, x);
		if (ret)
			return ret;
	}
	return NULL;
}


int IsCompleteBTree(BTNode* root)//判断一棵二叉树是否是完全二叉树
{
	//思路:完全二叉树的特性是前n-1层是满的,最后第n层的前k个是连续不间断的,后面不足无所谓。
	//那么就可以借助层序遍历,有左右子树就入队,没有对应的子树也入一个NULL进去,当第一次
	//遍历至NULL时,后面队列里的所有成员必须全是NULL,否则就不是完全二叉树(不满足连续)
	Queue q;
	QueueInit(&q);
	if (root == NULL)
	{
		return 0;
	}
	QueuePush(&q, root);
	while (QueueFront(&q) != NULL)
	{
		BTNode *front = QueueFront(&q);
		QueuePush(&q, front->_left);
		QueuePush(&q, front->_right);
		QueuePop(&q);
		free(front);
	}
	if (QueueEmpty(&q) == 0)
	{
		return 1;
	}
	else
	{
		while (QueueEmpty(&q))
		{
			if (QueueFront(&q) != NULL)
			{
				return 0;
			}
			QueuePop(&q);
		}
		return 1;
	}

}

void BTreePrevOrderNonR(BTNode* root)//前序非递归遍历二叉树
{
	//前序非递归遍历二叉树
	//思路:不用递归,可以用运营一个栈来模拟递归
	if (root == NULL)
	{
		return;
	}
	Stack s;
	StackInit(&s);
	BTNode *cur = root;
	while (cur || StackEmpty(&s))//cur不为空说明当前节点还可以遍历
	{	                         //stack不为空说明栈内元素可能还有孩子没有被遍历
		while (cur)
		{
			printf("%d ", cur->_data);
			StackPush(&s, cur);
			cur = cur->_left;
		}
		//运行到这说明已经到达了最左节点,该遍历该节点的右子树了
		BTNode *top = StackTop(&s);
		cur = top->_right;
		//此处用cur记录了top的右节点,要及时出栈,否则如果有top有右子树,入栈后,就无法将top再出栈了
		StackPop(&s);
		
	}
	
}
void BTreeInOrderNonR(BTNode* root)//中序非递归遍历二叉树
{
	//思路与前序非递归类似,遇到一个节点时,先入栈,然后一直进入左子树
	Stack s;
	StackInit(&s);
	BTNode *cur = root;
	while (cur || StackEmpty(&s))//cur不为空说明当前节点还可以遍历
	{	                         //stack不为空说明栈内元素可能还有孩子没有被遍历
		while (cur)
		{
			StackPush(&s, cur);
			cur = cur->_left;
		}
		//运行到这儿说明已经到达最左节点,该输出该节点了
		BTNode *top = StackTop(&s);
		printf("%d ", top->_data);
		cur = top->_right;//这里说明左孩子,中根节点已经遍历完毕,该右孩子遍历了
		StackPop(&s);
	}
}
void BTreePostOrderNonR(BTNode* root)//后序非递归遍历二叉树
{
	//后序非递归会比前序中序复杂一点,复杂的点就在于它的遍历顺序是左右中,
	//当把左孩子遍历完,该遍历右孩子了,这里cur会来到中根节点,当右孩子遍历完,cur又来到
	//中根节点,如何判断是否已经遍历右孩子?是后序遍历的关键。
	Stack s;
	StackInit(&s);
	BTNode *cur = root;
	BTNode *last = NULL;//新定义一个last记录右孩子是否遍历过,遍历过则将top->_right赋给last
	while (cur || StackEmpty(&s))
	{
		while (cur)
		{
			StackPush(&s, cur);
			cur = cur->_left;
		}
		BTNode *top = StackTop(&s);
		//如果此时发现top无右孩子或者右孩子已经被遍历过了,则直接输出top的data
		if (top->_right == NULL || last == top->_right)
		{
			printf("%d ", top->_data);
			StackPop(&s);
		}
		else
		{
			//进行到这里说明top有右孩子且尚未遍历过
			cur = top->_right;
			last = top->_right;
			
		}
	}
}

##queue.h


typedef BTNode* QueueDataType;

typedef struct QueueNode
{
	QueueDataType _data;
	struct QueueNode* _next;
}QueueNode;

typedef struct Queue
{
	QueueNode* _head;
	QueueNode* _tail;
}Queue;

void QueueInit(Queue* q)
{
	assert(q);
	q->_head = NULL;
	q->_tail = NULL;
}

QueueNode* BuyQueueNode(QueueDataType x)
{
	QueueNode* node = (QueueNode*)malloc(sizeof(QueueNode));
	node->_data = x;
	node->_next = NULL;

	return node;
}

void QueuePush(Queue* q, QueueDataType x)
{
	assert(q);
	if (q->_tail == NULL)
	{
		q->_head = q->_tail = BuyQueueNode(x);
	}
	else
	{
		q->_tail->_next = BuyQueueNode(x);
		q->_tail = q->_tail->_next;
	}
}

void QueuePop(Queue* q)
{
	if (q->_head == NULL)
	{
		return;
	}
	else
	{
		QueueNode* next = q->_head->_next;
		free(q->_head);
		q->_head = next;

		if (q->_head == NULL)
		{
			q->_tail = NULL;
		}
	}
}

QueueDataType QueueFront(Queue* q)
{
	assert(q->_head);
	return q->_head->_data;
}

QueueDataType QueueBack(Queue* q)
{
	return q->_tail->_data;
}

size_t QueueSize(Queue* q)
{
	QueueNode* cur = q->_head;
	size_t size = 0;
	while (cur)
	{
		++size;
		cur = cur->_next;
	}

	return size;
}

// 空 返回0
// 非空 返回1
int QueueEmpty(Queue* q)
{
	if (q->_head == NULL)
		return 0;
	else
		return 1;
}

##stack.h

#pragma once
#include<stdio.h>
#include<windows.h>
#include<assert.h>
typedef BTNode* STDataType;
#define Stack_size 10
typedef struct Stack
{
	STDataType* _array;//数组指针
	size_t  _top; //栈顶 
	size_t  _end;//最大容量
}Stack;
// 栈的实现接口 
void StackInit(Stack* s)//栈的初始化
{
	assert(s);
	s->_array = (STDataType*)malloc(sizeof(STDataType)*Stack_size);
	s->_end = Stack_size;
	s->_top = 0;

}


void StackPush(Stack* s, STDataType x)//入栈
{
	assert(s);
	if (s->_end == s->_top)//栈已满
	{
		s->_end *= 2;
		s->_array = (STDataType*)realloc(s->_array, sizeof(STDataType)*(s->_end));
		s->_array[s->_top] = x;
		(s->_top)++;
	}
	else
	{
		s->_array[s->_top] = x;
		(s->_top)++;
	}
}


void Stack_print(Stack *s)
{
	if (s == NULL)
	{
		return;
	}
	while ((s->_top)--)
	{
		printf("%d\t", s->_array[s->_top]);
	}
}


void StackPop(Stack* s)//出栈
{
	assert(s);
	if (s->_top == 0)
	{
		printf("the stack is empty");
	}
	else
	{
		s->_top--;
	}
}


STDataType StackTop(Stack* s)//取栈顶元素
{
	assert(s);
	assert(s->_top);
	
		int num = s->_top;
		
		return  s->_array[(--num)];
	
}


size_t StackSize(Stack* s)//栈的长度
{
	assert(s);
	return s->_end;
}


int StackEmpty(Stack* s)//判断栈是否为空
{
	if (s->_top == 0)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

##test.c

#include"binarytree.h"


void test()
{
	int a[] = { 1, 2, 3, '#', '#',4,'#', '#', 5, 6,'#' ,'#' ,'#' };
	int index = 0;
	BTNode *root = BinaryTreeCreateByPrev(a, &index, '#');
	BTreePrevOrder(root);
	printf("\n");
	BTreeInOrder(root);
	printf("\n");
	BTreePostOrder(root);
	printf("\n");
	printf("该树有%d个节点\n", BTreeSize(root));
	printf("该树有%d个叶子节点\n", BTreeLeafSize(root));
	printf("该树第3层的节点数为%d\n", BTreeKLevelSize(root, 3));
	printf("该树的深度为%d\n", BTreeDepth(root));

	printf("%d\n", BTreeFind(root, 3)->_data);
	printf("%d\n", IsCompleteBTree(root));
	/*BTreePrevOrderNonR(root);
	printf("\n");
	BTreeInOrderNonR(root);
	printf("\n");
	BTreePostOrderNonR(root);*/
}

int main()
{
	test();
	system("pause");
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值