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);
}