数组结构:链式结构二叉树

1.实现链式结构二叉树

用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给结点的左孩子和右孩子所在的链结点的存储地址,其结构如下:

//定义二叉树的链式结构
typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

二叉树的创建方式比较复杂,为了更好的步入到二叉树内容中,我们先手动创建一棵链式二叉树。


BTNode* BuyNode(BTDataType x)
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->left = newnode->right = NULL;

	return newnode;
}
void CreatTree()
{
	BTNode* node1 = BuyNode(1);
	BTNode* node2 = BuyNode(2);
	BTNode* node3 = BuyNode(3);
	BTNode* node4 = BuyNode(4);


	node1->left = node2;
	node1->right = node3;
	node2->left = node4;
}

回顾二叉树的概念,二叉树分为空树和非空二叉树,非空二叉树由根结点,根结点的左子树,根结点的右子树组成的 根结点的左子树和右子树分别是由子树的结点,子树结点的左子树和子树结点的右子树组成,因此二叉树定义是递归式的,后序链式二叉树的操作中基本都是按照该概念实现的。

2.实现链式二叉树书各个接口

//前序遍历
void PreOrder(BTNode* root);

//中序遍历
void InOrder(BTNode* root);

//后序遍历
void PostOrder(BTNode* root);

// ⼆叉树结点个数
int BinaryTreeSize(BTNode * root);

//二叉树叶子结点个数
int BinaryTreeLevelSize(BTNode* root);

//二叉树第k层结点个数
int BinaryTreeLevelkSize(BTNode* root, BTDataType k);

//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root);

//二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

//二叉树的销毁
void BinaryTreeDestory(BTNode** root);

//层序遍历
void LevelOrder(BTNode* root);

//判断是否为完全二叉树
bool BinaryTreeComplete(BTNo

2.1前中后序遍历 

二叉树的操作离不开树的遍历,我们先来看看二叉树的遍历有哪些方式: 

 

2.1.1遍历规则

1.前序遍历(Preorder Traversal 亦称先序遍历):访问根结点的操作发生在遍历其左右子树之前。访问顺序为:根结点、左子树、右子树 。

2.中序遍历(Inorder Traversal亦称中序遍历):访问根结点的操作发生在遍历其左右子树之中。访问顺序为:左子树、根结点、右子树。

3.后序遍历(Postorder Traversal):访问根节点的操作发生在遍历其左右子树之后。访问顺序为:左子树、右子树、根结点。

代码实现:

//前序遍历
void PreOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	printf("%d ", root->data);
	PreOrder(root->left);
	PreOrder(root->right);
}

//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		return;
	}
	InOrder(root->left);
	printf("%d ", root->data);
	InOrder(root->right);
}

 

前序遍历结果:1 2 3 4 5 6

中序遍历结果:3 2 1 5 4 6 

 后序遍历结果:3 2 5 6 4 1

2.2结点个数以及高度等

2.2.1二叉树的结点个数

二叉树的结点个数=根结点+左节点个数+右节点个数

// ⼆叉树结点个数
int BinaryTreeSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return 1 + BinaryTreeSize(root->left) + BinaryTreeSize(root->right);
}

2.2.2二叉树的叶子结点个数

叶子结点就是没有孩子结点的结点。当根结点为空时返回0,当结点的左右孩子结点都为NULL时此节点为叶子结点,因此我们只需要求出左右子树的叶子节点的个数相加就是二叉树的叶子结点个数,代码如下:

//二叉树叶子结点个数
int BinaryTreeLevelSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left ==NULL && root->right == NULL)
	{
		return 1;
	}
	return BinaryTreeLevelSize(root->left) + BinaryTreeLevelSize(root->right);
}

2.2.3二叉树第k层结点个数

我们需要一个变量k来说明求的是第几层的结点个数,我们需要采用递归的方式去求每次调用函数的时候都需要k-1,由于根结点就是第一层所以k==1时返回1,根结点为NULL时返回0.

//二叉树第k层结点个数
int BinaryTreeLevelkSize(BTNode* root, BTDataType k)
{
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelkSize(root->left, k - 1)+
	BinaryTreeLevelkSize(root->right, k - 1);
}

 2.2.4二叉树的深度

//二叉树的深度/高度
int BinaryTreeDepth(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int leftdeep = BinaryTreeDepth(root->left);
	int rightdeep = BinaryTreeDepth(root->right);

	return leftdeep > rightdeep ? leftdeep + 1 : rightdeep + 1;
}

 2.2.5二叉树查找值为x的结点

根结点为NULL时直接点返回空指针,当结点里面的数据域和x相等时返回该节点,定义两个结构体指针leftfind、rightfind用根的左右子树嵌套调用函数当leftfind 或者rightfind不为空时则找到了返回该指针。

//二叉树查找值为x的结点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	BTNode* leftfind = BinaryTreeFind(root->left, x);
	if (leftfind)
	{
		return leftfind;
	}
	BTNode* rightfind = BinaryTreeFind(root->right, x);
	if (rightfind)
	{
		return rightfind;
	}
	return NULL;
}

2.2.6二叉树的销毁

//二叉树的销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestory(&((*root)->left));
	BinaryTreeDestory(&((*root)->right));
	free(*root);
	*root = NULL;
}

3.层序遍历

除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历,设二叉树的根结点所在层数为1,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的树根结点,然后从左到右访问第二层上的结点,接着时第三层的结点,以此类推,自上而下,自左至右逐层访问树的结点。

实现层序遍历我们需要额外借助队列这个数据结构。


//层序遍历
void LevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		//取队头,打印
		BTNode* front = QueueFront(&q);
		printf("%d ", front->data);
		//删除队头
		QueuePop(&q);
		//队头结点的左右孩子结点入队尾
		if (front->left)
		{
			QueuePush(&q, front->left);
		}
		if (front->right)
		{
			QueuePush(&q, front->right);
		}

	}

	//销毁
	QueueDestory(&q);
}

4.判断是否为完全二叉树

如果最后一层的空结点后面全部都是空结点的话就是完全二叉树,如果中间有不是空结点的话就不是完全二叉树。

//判断是否为完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	//将根入队列
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		//取队头,打印
		BTNode* front = QueueFront(&q);
		//删除队头
		QueuePop(&q);
		if (front == NULL)
		{
			break;
		}
		//将头节点的左右孩子结点入队列
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}
	//如果剩下的结点全部为空则是完全二叉树
	//反之则不是二叉树
	while (!QueueEmpty(&q))
	{
		BTNode* top = QueueFront(&q);
		QueuePop(&q);
		if (top != NULL)
		{
			QueueDestory(&q);
			return false;
		}
		QueueDestory(&q);
		return true;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值