树的定义与性质
树:在数据结构中,树是用来概括这种传递关系的一种数据结构。
结点:数据结构中把树枝分叉处、树叶、树根抽象为结点。
根结点:树根
叶子结点:树叶
边:茎干和树枝
一棵树最多存在一个根节点
叶子结点不再延伸出新的结点
一条边只用来连接两个结点(一个端点一个)
树:由若干个结点和若干个边组成的数据结构,且在树中的结点不能被边连成环。
树的性质:
- 树可以没有结点,即空树
- 树的层次:从根结点开始算起,根结点为第一层,根结点子树的根结点为第二次…
- 度:结点的子树棵数
- 树的度:树中结点的最大的度
- 由于一条边连接两个结点,且树中不存在环,因此对有n个结点的树,边数一定是n-1。且满足连通、边数等于顶点数减1的结构一定是一棵树
- 叶子结点:度0的结点。因此当树中只有一个结点(即只有根结点)时,根结点也算叶子结点
- 结点的深度:从根结点(深度为1)开始自顶向下逐层累加至该结点时的深度值
- 结点的高度:从最底层叶子结点(高度为1)开始自底向上逐层累加至该结点时的高度值。
- 树的深度:树中结点的最大深度
- 树的高度:树中结点的最大高度
- 森林:多棵树组合在一起。森林是若干棵树的集合
二叉树的递归定义
二叉树递归定义:
- 要么二叉树没有根结点,是一颗空树
- 要么二叉树由根结点、左子树、右子树组成,且左子树和右子树都是二叉树
二叉树与度为2的树的区别: - 对树来说,结点的子树不区分左右顺序的,度为2的树只能说明树中每个结点的子结点个数不超过2.
- 二叉树满足每个结点的子结点个数不超过2,要严格区分左右子树
特殊的二叉树:
- 满二叉树:每一层的结点个数都达到了当层能达到的最大结点数。
- 完全二叉树:除了最下面一层之外,其余的结点个数都达到了当层能达到的最大结点数,且最下面一层只从左至右连续存在若干结点,而这些连续结点右边的结点全部不存在。
二叉树的存储结构与基本操作
- 二叉树的存储结构
struct node{
typename data; //数据域
node* lchild; //指向左子树根结点的指针
node* rchild; //指向右子树根结点的指针
};
由于在二叉树建树前根结点不存在,因此其地址一般设为NULL
node* root = NULL;
新建结点
node* newNode(int v){
node* Node = new node; //申请一个node型变量的地址空间
Node->data = v; //结点权值v
Node->lchild = Node->rchild = NULL; //初始化状态下没有左右孩子
return Node; //返回新建结点的地址
}
- 二叉树结点的查找、修改
查找:在给定数据域的条件下,在二叉树中找到所有数据域为给定数据域的结点,并将它们数据域修改为给定的数据域。
递归式:对当前结点的左子树和右子树分别递归
递归边界:当前结点为空时到达死胡同
先判断当前结点是否是需要查找的结点:
如果是,则对其修改
如果不是,则分别往该结点的左孩子和右孩子递归,直到当前结点为NULL
void search(node* root, int x, int newdata)
{
if(root == NULL)
{
return; //空树,死胡同(递归边界)
}
if(root->data = x) //找到数据域为x的结点,把它修改成newdata
{
root->data = newdata;
}
search(root->lchild, x, newdata); //往左子树搜索x(递归式)
search(root->rchild, x, newdata); //往右子树搜索x(递归式)
}
search函数为什么不需要加引用:因为该函数中修改的是指针root指向的内容,而不是root本身,对指针指向的结点内容的修改时不需要加引用的。
- 二叉树结点的插入
二叉树结点的插入位置:数据域在二叉树中查找失败的位置。
//insert函数将在二叉树中插入一个数据域为x的新结点
//注意根结点指针root要使用引用,否则插入不会成功
void insert(node* &root, int x)
{
if(root == NULL) //空树,说明查找失败,也即插入位置(递归边界)
{
root = newNode(x);
return;
}
if(由二叉树的性质,x应该插在左子树)
{
insert(root->lchild, x); //往左子树搜索(递归式)
}
else
{
insert(root->rchild, x); //往右子树搜索(递归式)
}
}
根结点指针root使用了引用&。即在函数中修改root会直接修改原变量。
判断是否加引用:如果函数中需要新建结点,即对二叉树的结构做出修改,就需要加引用;如果只修改当前已有结点的内容,或仅仅是遍历树,就不用加引用。
注意:在新建结点之后,务必令新结点的左右指针域为NULL,表示这个新结点暂时没有左右指针。
- 二叉树的创建
把需要插入的数据存储在数组中,然后再将它们使用insert函数一个个插入二叉树中,并最终返回根结点的指针root。
//二叉树的建立
node* Create(int data[], int n)
{
node* root = NULL; //新建空根结点root
for(int i = 0; i < n; i++)
{
insert(root, data[i]); //将data[0]~data[n-1]插入二叉树中
}
return root; //返回根结点
}