二叉树

1. 熟悉树的概念以及相关概念

树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因 为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:每个结点有零个或多 个子结点;没有父结点的结点称为根结点;每一个非根结点有且只有一个父结点;除了根结点外,每个子结 点可以分为多个不相交的子树 。

节点的度:一个节点含有的子树的个数称为该节点的度; 如上图:A的为6 叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I...等节点为叶节点
非终端节点或分支节点:度不为0的节点; 如上图:D、E、F、G...等节点为分支节点 双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点 孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点 树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推; 树的高度或深度:树中节点的最大层次; 如上图:树的高度为4 堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为兄弟节点
节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先 子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙 森林:由m(m>=0)棵互不相交的树的集合称为森林; 

树的表示方法::双亲表 示法,孩子表示法、孩子兄弟表示法等等。最常用的是孩子兄弟表示法。

struct Node
{
	struct Node *_firstChild1;		//第一个孩子节点
	struct Node *_pNextBrother;		//指向其下一个兄弟节点
	DataType _data;					//节点中的数据域
};


2. 了解树的存储方式以及其区别

二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。

顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的 浪费。而现实中使用中只有堆才会使用数组来存储,关于堆我们后面的章节会专门讲解。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表 中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结 点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链,后面课程学到高阶数据 结构如红黑树等会用到三叉链。


3. 了解树的应用场景

文件系统
4. 熟悉二叉树的基本概念以及性质

概念:一棵二叉树是节点的一个有限集合,该集合或者为空,或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

性质:1. 每个结点最多有两棵子树,即二叉树不存在度大于2的结点。 
           2. 二叉树的子树有左右之分,其子树的次序不能颠倒。
5. 熟悉满二叉树和完全二叉数,并掌握其区别

满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是 说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。

完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K 的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对 应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树(完全二叉树是满二叉树从最后一个节点往前面删减形成的二叉树)。


6. 实现链式数据结构的以下基本操作:

typedef char BTDataType;

typedef struct BTNode
{
struct BTNode* _pLeft;
struct BTNode* _pRight;
BTDataType _data;
}BTNode;

typedef struct {
    BTNode *node;    // 构建出的二叉树的根结点
    int used;    // 构建过程中使用的序列长度
}Result;


// 1. 创建二叉树
BTNode* CreateBinTree(BTDataType* array, int size);

Result CreateBinTree(BTDataType array[], int size)
{
	Result result;
	if (size == 0)
	{
		result.node = NULL;
		result.used = 0;
		return result;
	}

	if (array[0] == '#')
	{
		result.node = NULL;
		result.used = 1;
		return result;
	}

	//根
	BTNode *pRoot = (BTNode *)malloc(sizeof(BTNode));
	pRoot->_data = array[0];

	//左子树
	Result leftR = CreateBinTree(array + 1, size - 1);

	//右子树
	Result rightR = CreateBinTree(array + 1 + leftR.used, size - 1 - leftR.used);

	pRoot->_pLeft = leftR.node;	
	pRoot->_pRight = rightR.node;	

	result.node = pRoot;
	result.used = 1 + leftR.used + rightR.used;
	return result;
}



// 拷贝二叉树
BTNode* CopyBinTree(BTNode* pRoot);

BTNode* CopyBinTree(BTNode* pRoot)
{
	BTNode *newNode = NULL;
	if (pRoot == NULL)
		return NULL;
	else
	{
		newNode = (BTNode *)malloc(sizeof(BTNode));
		newNode->_data = pRoot->_data;
		newNode->_pLeft = CopyBinTree(pRoot->_pLeft);
		newNode->_pRight = CopyBinTree(pRoot->_pRight);
		
	}
	return newNode;
}



// 销毁二叉树
void DestroyBinTree(BTNode** pRoot);

void DestroyBinTree(BTNode** pRoot)
{
	assert(pRoot);
	if (*pRoot)
	{
		DestroyBinTree(&((*pRoot)->_pLeft));
		DestroyBinTree(&((*pRoot)->_pRight));
		free(*pRoot);
		*pRoot = NULL;
	}
}


// 二叉树的三种遍历方式
void PreOrder(BTNode* pRoot);

void PreOrder(BTNode* pRoot)	//前序遍历
{
	//空树
	assert(pRoot);
		return;
	//根节点
	printf("%c ", pRoot->_data);

	//左子树
	PreOrder(pRoot->_pLeft);

	//右子树
	PreOrder(pRoot->_pRight);
}


void PreOrderNor(BTNode* pRoot);

#include <stack>
using std::stack;
void PreOrderNor(BTNode* pRoot)		//非递归前序遍历
{
	stack<BTNode *> s;
	BTNode *cur = pRoot;
	while (!s.empty() || cur != NULL)
	{
		while (cur != NULL)
		{
			printf("%c ", cur->_data);
			s.push(cur);
			cur = cur->_pLeft;
		}

		BTNode *top = s.top();
		s.pop();

		cur = cur->_pRight;
	}
	printf("\n");
}


void InOrder(BTNode* pRoot);

void InOrder(BTNode* pRoot)		//中序遍历
{
	//空树
	assert(pRoot);
		return;

	//左子树
	InOrder(pRoot->_pLeft);

	//根
	printf("%c ", pRoot->_data);

	//右子树
	InOrder(pRoot->_pRight);
}


void InOrderNor(BTNode* pRoot);

void InOrderNor(BTNode* pRoot)		//非递归中序遍历
{
	stack<BTNode *> s;
	BTNode *cur = pRoot;

	while (!s.empty() || cur != NULL) {
		while (cur != NULL) {
			s.push(cur);
			cur = cur->_pLeft;
		}

		BTNode *top = s.top();
		s.pop();
		printf("%c ", top->_data);

		cur = top->_pRight;
	}

	printf("\n");
}


void PostOrder(BTNode* pRoot);

void PostOrder(BTNode* pRoot)		//后序遍历
{
	//空树
	assert(pRoot);
		return;

	//左子树
	PostOrder(pRoot->_pLeft);

	//右子树
	PostOrder(pRoot->_pRight);

	//根
	printf("%c ", pRoot->_data);
}


void PostOrderNor(BTNode* pRoot);

void PostOrderNor(BTNode* pRoot)		非递归后序遍历
{
	stack<BTNode *> s;
	BTNode *cur = pRoot;
	BTNode *last = NULL;	// 上一次被完整遍历完的树的根结点

	while (!s.empty() || cur != NULL) {
		while (cur != NULL) {
			s.push(cur);
			cur = cur->_pLeft;
		}

		BTNode *top = s.top();
		if (top->_pRight == NULL) {
			printf("%c ", top->_data);
			s.pop();

			last = top;
		}
		else if (top->_pRight == last) {

			printf("%c ", top->_data);
			s.pop();

			last = top;
		}
		else {
			cur = top->_pRight;
		}
	}

	printf("\n");
}


void LevelOrder(BTNode* pRoot);

#include <queue>
using std::queue;
void LevelOrder(BTNode* pRoot)		//层序遍历
{
	assert(pRoot);
	printf("\n");

	queue<BTNode *> q;
	q.push(pRoot);	
	while (!q.empty()) {
		BTNode *front = q.front();
		q.pop();

		printf("%c ", front->_data);
		if (front->_pLeft != NULL) {
			q.push(front->_pLeft);
		}
		if (front->_pRight != NULL) {
			q.push(front->_pRight);
		}
	}
	printf("\n");
}


// 获取二叉树中节点的个数
int GetNodeCount(BTNode* pRoot);

int GetNodeCount(BTNode* pRoot)
{
	
	//递推
	//空树
	assert(pRoot);
		return 0;
	
	//左子树节点个数
	int left = GetNodeCount(pRoot->_pLeft);

	//右子树节点个数
	int right = GetNodeCount(pRoot->_pRight);

	return left + right + 1;
	
}


// 求二叉树的高度
int Height(BTNode* pRoot);

int Height(BTNode* pRoot)
{
	//空树
	assert(pRoot);
		return 0;
	
	//左子树高度
	int left = Height(pRoot->_pLeft);

	//右子树高度
	int right = Height(pRoot->_pRight);

	return ((left > right) ? left : right) + 1;
}


// 检测二叉树是否平衡O(N^2)
int IsBalanceTree(BTNode* pRoot);

//平衡二叉树:左子树是平衡二叉树 && 右子树是平衡二叉树 && 左右子树的高度不超过1
int IsBalanceTree(BTNode* pRoot)
{
	if (pRoot == NULL)
		return 1;
	int left = Height(pRoot->_pLeft);
	int right = Height(pRoot->_pRight);
	
	return IsBalanceTree(pRoot->_pLeft) && IsBalanceTree(pRoot->_pRight) && (abs(left - right) <= 1);
}


// 检测二叉树是否平衡O(N)
int IsBalanceTree_P(BTNode* pRoot, int* height);

int IsBalanceTree_P(BTNode* pRoot, int* height)
{
	//空树
	if (pRoot == NULL)
	{
		return 1;
	}

	int left = 0;
	int right = 0;
	if (IsBalanceTree_P(pRoot->_pLeft, &left) || IsBalanceTree_P(pRoot->_pRight, &right))
	{
		int ret = left - right;
		if ((ret >= 1) || (ret <= -1))
			return 1;
	}

	return 0;
}


// 获取二叉数中叶子节点的个数
int GetLeafNodeCount(BTNode* pRoot);

int GetLeafNodeCount(BTNode* pRoot)
{
	//空树
	assert(pRoot);
		return 0;

	//只有根节点的数
	if ((pRoot->_pLeft == NULL) && (pRoot->_pRight == NULL))
		return 1;

	//左子树叶子节点个数
	int left = GetLeafNodeCount(pRoot->_pLeft);

	//右子树叶子节点个数
	int right = GetLeafNodeCount(pRoot->_pRight);

	return left + right;
}


// 获取二叉树第K层节点的个数
int GetKLevelNodeCount(BTNode* pRoot, int K);

int GetKLevelNodeCount(BTNode* pRoot, int K)
{
	//空树
	assert(pRoot);
		return 0;

	//第一层
	if (K == 1)
		return 1;

	//左子树
	int left = GetKLevelNodeCount(pRoot->_pLeft, K - 1);

	//右子树
	int right = GetKLevelNodeCount(pRoot->_pRight, K - 1);

	return left + right;
}


// 获取二叉树中某个节点的双亲节点
BTNode* GetNodeParent(BTNode* pRoot, BTNode* pNode);

BTNode* GetNodeParent(BTNode* pRoot, BTNode* pNode)
{
	if ((pRoot == NULL) || (pNode == pRoot) || (pNode == NULL))
		return NULL;

	if ((pRoot->_pLeft != NULL) || (pNode->_pRight != NULL))
		return pNode;

	return GetNodeParent(pRoot, pNode);
}


// 求二叉树的镜像
void Mirror(BTNode* pRoot);

void Mirror(BTNode* pRoot)
{
	if ((pRoot == NULL) || ((pRoot->_pLeft == NULL) && (pRoot->_pRight == NULL)))
		return;

	BTNode *temp = pRoot->_pLeft;
	pRoot->_pLeft = pRoot->_pRight;
	pRoot->_pRight = temp;

	if (pRoot->_pLeft != NULL)
		Mirror(pRoot->_pLeft);

	if (pRoot->_pRight != NULL)
		Mirror(pRoot->_pRight);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值