二叉树的概念与链式存储实现

二叉树与堆

  • 二叉树
    • 一:二叉树的概念与性质
    • 二:二叉树的存储结构
      • (1)链式存储
      • (2)顺序存储
    • 三:二叉树的链式存储结构及实现
      • (1)二叉树链式存储结构
      • (2)二叉树链式存储前序遍历
      • (3)二叉树链式存储中序遍历
      • (4)二叉树链式存储后序遍历
      • (5)二叉树节点个数
      • (6)叶子节点个数
      • (7)树高
      • (8)第k层节点个数
      • (9)二叉树查找值为X的节点
      • (10)层序遍历 ( 利用队列解决层序遍历)
      • (11)判断二叉树是否是完全二叉树
      • (12)二叉树销毁
    • BinaryTree.c

二叉树

一:二叉树的概念与性质

概念:一棵二叉树是结点的一个有限集合,该集合:
1:或者为空;由一个根节点加上两棵别称为左子树和右子树的二叉树组成
2: 二叉树不存在度大于2的结点; 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树

性质:

  1. 若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2的i次方减1个结点.
  2. 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2的h次方-1
  3. 对任何一棵二叉树, 如果度为0其叶结点个数为n0,度为2的分支节点结点个数为n2,则有n0=n2+1
  4. 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1)
  5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
  6. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
  7. 若2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
  8. 若2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子

二:二叉树的存储结构

二叉树一般分为两种存储结构,一种是顺序结构,一种是链式结构。

(1)链式存储

概念:二叉树的链式存储结构是指用链表来表示一颗二叉树,即用链表来指示元素的逻辑关系;通常是在高阶数据结构红黑树等会使用该存储结构

(2)顺序存储

概念:顺序存储结构就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不会有空间浪费(例如:堆排序)

三:二叉树的链式存储结构及实现

(1)二叉树链式存储结构

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

BTNode* ByBTNode(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;
}

(2)二叉树链式存储前序遍历

// 二叉树前序遍历  根 左子树 右子树
void PreOrder(BTNode* root)
{
	//判断是否未NULL树
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->_data);
	//再递归访问左子树
	PreOrder(root->_left);
	//再递归访问右子树
	PreOrder(root->_right);
}

(3)二叉树链式存储中序遍历

// 二叉树中序遍历 左子树 根 右子树
void InOrder(BTNode* root)
{
	//判断是否未NULL树
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	//先递归访问左子树
	InOrder(root->_left);
	printf("%d ", root->_data);
	//再递归访问右子树
	InOrder(root->_right);

}

(4)二叉树链式存储后序遍历

//后序遍历 左子树 右子树 根
void PostOrder(BTNode* root)
{
	//先判断是否为空树
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	//先访问左子树
	PostOrder(root->_left);
	//再访问右子树
	PostOrder(root->_right);
	printf("%d ", root->_data);
}

(5)二叉树节点个数

//求二叉树节点个数
int TreeSize(BTNode* root)
{
	//1:如果为空则返回0
	//2:不为空则递归左子树和右子树
	return root == NULL ? 0 : TreeSize(root->_left) + TreeSize(root->_right) + 1;

}

(6)叶子节点个数

int TreeLeafSize(BTNode* root)
{
	//当节点为空时返回 0,此时为空树
	if (root == NULL)
	{
		return 0;
	}

	//节点的左子树与右子树同时为空是返回1,代表此时为叶子节点
	if (root->_left == NULL&&root->_right == NULL)
	{
		return 1;
	}

	//递归到叶子节点
	return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}

(7)树高

int TreeHeight(BTNode* root)
{
	//根节点为空时为空树
	if (root == NULL)
	{
		return 0;
	}

	//1:用变量接收左右两边子树的高度
	//2:先递归完左子树高度
	//3:再递归右子树高度
	//最后比较左子树和右子树哪边大,再加根节点高度就为树的高度
	int leftheight = TreeHeight(root->_left);
	int rightheight = TreeHeight(root->_right);

	return leftheight > rightheight ? leftheight + 1 : rightheight + 1;

}

(8)第k层节点个数

int TreeKSize(BTNode* root, int k)
{
	
	if (root == NULL)
	{
		return 0;
	}

	//k==1时表示层数为1时
	if (k == 1)
	{
		return 1;
	}

	//逐层递归计算节点个数
	return TreeKSize(root->_left, k - 1) + TreeKSize(root->_right, k - 1);
}

(9)二叉树查找值为X的节点

BTNode* TreeFind(BTNode* root, BTDataType x)
{
	//该节点为空返回空
	if (root == NULL)
	{
		return NULL;
	}

	//节点值==x,返回root
	if (root->_data == x)
	{
		return root;
	}

	//找递归左子树是否存在,存在则返回ret1;
	BTNode* ret1 = TreeFind(root->_left, x);
	if (ret1)
	{
		return ret1;
	}

	//找递归右子树是否存在,存在则返回ret2
	BTNode* ret2 = TreeFind(root->_right, x);
	if (ret2)
	{
		return ret2;
	}

	//不存在返回空
	return NULL;
}

(10)层序遍历 ( 利用队列解决层序遍历)

void LevelOeder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	
	//根节点不为空时,从队尾插入
	if (root)
	{
		QueuePush(&q, root);
	}

	printf(" LevelOeder:");
	//队列不为NULL时,一直插入
	while (!QueueEmpty(&q))
	{
		//取队头元素
		QDataType front = QueueFront(&q);

		printf("%d ", front->_data);


		//判断是否存在左子树,存在就插入
		if (front->_left)
		{
			QueuePush(&q, front->_left);
		}

		//判断是否存在右子树,存在就插入
		if (front->_right)
		{
			QueuePush(&q, front->_right);
		}

		//删除队头元素
		QueuePop(&q);
		
	}
	
	QueueDestroy(&q);
}

(11)判断二叉树是否是完全二叉树

bool BinaryTreeComplete(BTNode* root)
{
	//利用层序遍历思路,用队列解决判断是否是完全二叉树
	Queue q;

	//初始化
	QueueInit(&q);
	//插入
	QueuePush(&q, root);

	while (!QueueEmpty(&q))//
	{
		BTNode* front = QueueFront(&q);//取队头元素保存
		QueuePop(&q);//删除队头元素

		if (front == NULL)//当元素为空时跳出判断
		{
			break;
		}
		else
		{
			//左右子树插入
			QueuePush(&q, front->_left);
			QueuePush(&q, front->_right);
		}
	}

	//出到空之后全是空,则是完全二叉树
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}

	QueueDestroy(&q);
	return true;
}

(12)二叉树销毁

void TreeDestroy(BTNode* root)
{
	//判断是否为空
	if (root == NULL)
	{
		return;
	}

	//后序遍历销毁
	TreeDestroy(root->_left);
	TreeDestroy(root->_right);

	free(root);

}

BinaryTree.c

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

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType _data;
	struct BinaryTreeNode* _left;
	struct BinaryTreeNode* _right;
}BTNode;

BTNode* ByBTNode(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 PreOrder(BTNode* root)
{
	//判断是否未NULL树
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	printf("%d ", root->_data);
	//再递归访问左子树
	PreOrder(root->_left);
	//再递归访问右子树
	PreOrder(root->_right);
}


// 二叉树中序遍历 左子树 根 右子树
void InOrder(BTNode* root)
{
	//判断是否未NULL树
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}
	//先递归访问左子树
	InOrder(root->_left);
	printf("%d ", root->_data);
	//再递归访问右子树
	InOrder(root->_right);

}

//后序遍历 左子树 右子树 根
void PostOrder(BTNode* root)
{
	//先判断是否为空树
	if (root == NULL)
	{
		printf("NULL ");
		return;
	}

	//先访问左子树
	PostOrder(root->_left);
	//再访问右子树
	PostOrder(root->_right);
	printf("%d ", root->_data);
}


//求二叉树节点个数
int TreeSize(BTNode* root)
{
	//1:如果为空则返回0
	//2:不为空则递归左子树和右子树
	return root == NULL ? 0 : TreeSize(root->_left) + TreeSize(root->_right) + 1;

}

//求叶子节点个数
int TreeLeafSize(BTNode* root)
{
	//当节点为空时返回 0,此时为空树
	if (root == NULL)
	{
		return 0;
	}

	//节点的左子树与右子树同时为空是返回1,代表此时为叶子节点
	if (root->_left == NULL&&root->_right == NULL)
	{
		return 1;
	}

	//递归到叶子节点
	return TreeLeafSize(root->_left) + TreeLeafSize(root->_right);
}


//求树高
int TreeHeight(BTNode* root)
{
	//根节点为空时为空树
	if (root == NULL)
	{
		return 0;
	}

	//1:用变量接收左右两边子树的高度
	//2:先递归完左子树高度
	//3:再递归右子树高度
	//最后比较左子树和右子树哪边大,再加根节点高度就为树的高度
	int leftheight = TreeHeight(root->_left);
	int rightheight = TreeHeight(root->_right);

	return leftheight > rightheight ? leftheight + 1 : rightheight + 1;

}

//求第k层节点个数
int TreeKSize(BTNode* root, int k)
{
	
	if (root == NULL)
	{
		return 0;
	}

	//k==1时表示层数为1时
	if (k == 1)
	{
		return 1;
	}

	//逐层递归计算节点个数
	return TreeKSize(root->_left, k - 1) + TreeKSize(root->_right, k - 1);
}

//二叉树查找值为X的节点
BTNode* TreeFind(BTNode* root, BTDataType x)
{
	//该节点为空返回空
	if (root == NULL)
	{
		return NULL;
	}

	//节点值==x,返回root
	if (root->_data == x)
	{
		return root;
	}

	//找递归左子树是否存在,存在则返回ret1;
	BTNode* ret1 = TreeFind(root->_left, x);
	if (ret1)
	{
		return ret1;
	}

	//找递归右子树是否存在,存在则返回ret2
	BTNode* ret2 = TreeFind(root->_right, x);
	if (ret2)
	{
		return ret2;
	}

	//不存在返回空
	return NULL;
}

//层序遍历  利用队列解决层序遍历
void LevelOeder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	
	//根节点不为空时,从队尾插入
	if (root)
	{
		QueuePush(&q, root);
	}

	printf(" LevelOeder:");
	//队列不为NULL时,一直插入
	while (!QueueEmpty(&q))
	{
		//取队头元素
		QDataType front = QueueFront(&q);

		printf("%d ", front->_data);


		//判断是否存在左子树,存在就插入
		if (front->_left)
		{
			QueuePush(&q, front->_left);
		}

		//判断是否存在右子树,存在就插入
		if (front->_right)
		{
			QueuePush(&q, front->_right);
		}

		//删除队头元素
		QueuePop(&q);
		
	}
	
	QueueDestroy(&q);
}


//判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	//利用层序遍历思路,用队列解决判断是否是完全二叉树
	Queue q;

	//初始化
	QueueInit(&q);
	//插入
	QueuePush(&q, root);

	while (!QueueEmpty(&q))//
	{
		BTNode* front = QueueFront(&q);//取队头元素保存
		QueuePop(&q);//删除队头元素

		if (front == NULL)//当元素为空时跳出判断
		{
			break;
		}
		else
		{
			//左右子树插入
			QueuePush(&q, front->_left);
			QueuePush(&q, front->_right);
		}
	}

	//出到空之后全是空,则是完全二叉树
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		if (front != NULL)
		{
			QueueDestroy(&q);
			return false;
		}
	}

	QueueDestroy(&q);
	return true;
}


//二叉树销毁
void TreeDestroy(BTNode* root)
{
	//判断是否为空
	if (root == NULL)
	{
		return;
	}

	//后序遍历销毁
	TreeDestroy(root->_left);
	TreeDestroy(root->_right);

	free(root);

}

int main()
{
	BTNode* n1 = ByBTNode(1);
	BTNode* n2 = ByBTNode(2);
	BTNode* n3 = ByBTNode(3);
	BTNode* n4 = ByBTNode(4);
	BTNode* n5 = ByBTNode(5);
	BTNode* n6 = ByBTNode(6);

	BTNode* n7 = ByBTNode(7);
	n3->_right = n7;


	n1->_left = n2;
	n2->_left = n3;
	n1->_right = n4;
	n4->_left = n5;
	n4->_right = n6;

	//前序遍历
	PreOrder(n1);
	printf("
");

	//中序遍历
	InOrder(n1);
	printf("
");

	//后续遍历
	PostOrder(n1);
	printf("
");

	//层序遍历
	LevelOeder(n1);
	printf("
");
	//求二叉树节点个数
	printf("TreeSize:%d
", TreeSize(n1));

	//求二叉树叶子节点
	printf("TreeLeafSize:%d
", TreeLeafSize(n1));

	//求二叉树的高度
	printf("TreeHeight:%d
", TreeHeight(n1));

	//求第k层的节点个数 
	printf("TreeKSize:%d
", TreeKSize(n1, 3));

	//二叉树查找值为X的节点
	BTNode* ret = TreeFind(n1, 7); 
	printf("ret=%d val=%d
", ret, ret->_data);

	//判断二叉树是否是完全二叉树
	printf("BinaryTreeComplete:%d", BinaryTreeComplete(n1));

	TreeDestroy(n1);
	n1 = NULL;

	return 0;
}