数据结构——树概念
节点深度:对任意节点x,x节点的深度表示为根节点到x节点的路径长度。所以根节点深度为0,第二层节点深度为1,以此类推
节点高度:对任意节点x,叶子节点到x节点的路径长度就是节点x的高度
树的深度:一棵树中节点的最大深度就是树的深度,也称为高度
父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点
子节点:一个节点含有的子树的根节点称为该节点的子节点
节点的层次:从根节点开始,根节点为第一层,根的子节点为第二层,以此类推
兄弟节点:拥有共同父节点的节点互称为兄弟节点
度:节点的子树数目就是节点的度
叶子节点:度为零的节点就是叶子节点
祖先:对任意节点x,从根节点到节点x的所有节点都是x的祖先(节点x也是自己的祖先)
后代:对任意节点x,从节点x到叶子节点的所有节点都是x的后代(节点x也是自己的后代)
森林:m颗互不相交的树构成的集合就是森林
(一)、二叉树
树的任意节点至多包含两颗子树。
1、二叉树:最多有两颗子树的树被称为二叉树。
2、满二叉树:叶子节点都在同一层且除叶子节点外的所有节点都有两个子节点。
3、完全二叉树:对于一颗深度为d的二叉树,除d层外的所有节点构成满二叉树,且第d层所有节点从左至右连续地紧密排列。
4、 二叉查找树(Binary Search Tree)是指一棵空树或者具有下列性质的二叉树:
1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
2、 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
3、 任意节点的左、右子树也分别为二叉查找树;
4、 没有键值相等的节点。
5、平衡二叉树:含有相同节点的二叉查找树可以有不同的形态,而二叉查找树的平均查找长度与树的深度有关,所以需要找出一个查找平均长度最小的一棵,那就是平衡二叉树,具有以下性质:
(一)、要么是棵空树,要么其根节点左右子树的深度之差的绝对值不超过1;
(二)、其左右子树也都是平衡二叉树;
(三)、二叉树节点的平衡因子定义为该节点的左子树的深度减去右子树的深度。
则平衡二叉树的所有节点的平衡因子只可能是-1,0,1。
(二)、二叉树的遍历
二叉树遍历均有两种比较实用的算法:一种为递归算法,一种则是非递归的算法
先序遍历
如果二叉树为空,则进行空操作,否则进行以下操作:
1.访问根节点
2.先序遍历左子树
3.先序遍历右子树
递归算法:
void PreOrderTraversal(BinTree *BT){
if(BT) {
printf("%d",BT->Data);
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
}
非递归算法:
void PreOrderTraversal(BinTree *BT){
if (!BT)
return;
BinTree *P = BT;
stack<BinTree*>st;
while (P != NULL || !st.empty()){
while (P){
st.push(P);
cout << P->Value << endl;
P = P->Left;
}
if (!st.empty()) {
P = st.top();
st.pop();
P = P->Right;
}
}
}
后序遍历
1.后序遍历左节点
2.后序遍历右结点
3.访问根节点
递归算法:
void PreOrderTraversal(BinTree *BT){
if(BT){
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
printf("%d",BT->Data);
}
}
非递归算法:
void PreOrderTraversal(BinTree *BT){
if (!BT)
return;
BinTree *P = BT,*Flag = NULL;
stack<BinTree*>st;
while (P != NULL || !st.empty()){
if(P){ //走到最左边
st.push(P);
P = P->Left;
} else{
P = st.top();
if(P->Right != NULL && P->Right != Flag){ //右子树存在,并且未被访问
P = P->Right;
}else{
st.pop();
cout << P->value << endl;
Flag = P;
P = NULL;
}
}
}
}
层次遍历
二叉树的层次遍历就是按照二叉树的层次,从上到下,从左到右依次遍历,
为了实现这种遍历方式则需要用到之前所学到的队列
void travLevel ( BinTreeNode<T>* root ){
Queue<BinTreeNode<T>*> Q;
Q.enqueue ( root ); //根节点入队
while ( !Q.empty() ){
BinTreeNode<T>* x = Q.dequeue(); cout << x->data; //取出队首节点并访问之
if ( x->LeftChild ) Q.enqueue ( x->LeftChild ); //左孩子入队
if ( x->RightChild ) Q.enqueue ( x->RightChild ); //右孩子入队
}
}