树&二叉树
1.树
树的定义:树是n(n>=0)个结点的有限集合,当n=0时称为空树。对于任意一颗非空树应该满足以下条件:
a.有且仅有一个根节点
b.当n>1时,其余结点可以分为m个互不相交的有限集合T1,T2...Tm,其中每个集合又是一棵树,并且是根的子树
基本术语:
树中一个结点的孩子的个数称为树的度,其中拥有最大度的结点的度称为树的度。
度大于0的结点称为分支结点/非终端结点,度为0的结点称为叶子结点。
层次:结点的层次从树根开始定义,根节点为第一层。
深度:从根节点开始自顶向下累加
高度:从最下面的结点自底向上累加
有序树和无序树:结点的各个子树顺序有所谓(不能互换)则称为有序树,无所谓(可以随意互换)则称为无序树
路径和路径长度:从A结点到B结点所经过的所有结点序列,路径长度是这条路径上的结点个数
森林:m个树一起(m>=0)构成森林,如果给这m个树加一个共同的根节点,那么这个森林就变成了一棵树
树的性质:
结点数等于所有结点的度数加1
度为m的树第i层最多有mi-1个结点。
高度为h的m叉树最多有(mh-1)/(m-1)个结点
树的存储结构:
双亲表示法:用一组连续的空间来存储每个结点,每个结点中增加一个数据域作为伪指针,指向该结点的父节点对应的数组下标
//双亲表示法,根节点下标为0,其伪指针域为-1 typedef struct{ ElementType data; int parent; }node; typedef struct{ node N[MAX_SIZE]; int n; }Tree;
孩子表示法:链式存储结构,因为每个结点的结构需要一致,但是每个结点拥有的孩子数量又往往不同,因此父节点中只设一个指向孩子结点的指针,在孩子 结点中也加设一个指针域,指向它的下一个兄弟结点。
//孩子表示法 typedef struct child{ int n; child* next; }*nextChild; typedef struct{ ElementType data; child* firstChild; }node; typedef struct{ node N[MAX_SIZE]; int n,r; //结点数量和根节点 }Tree;
孩子兄弟表示法:孩子表示法需要区别父节点和孩子结点,而孩子兄弟表示法中所有结点的结构都是一样的
typedef struct node{ ElementType data; struct node* firstChild; struct node* nextSibling; }node,*Tree;
树、森林、二叉树的转换:树转换为二叉树就是将树用孩子兄弟表示法来存储各个结点,得到的链式结构对应的就是相应的二叉树,森林转换为二叉树的时候,先将森林中的每棵树转化为二叉树,再将得到的二叉树的根节点看作是同一层次的兄弟,用第一个根节点的右指针域指向第二个根节点,第二个根节点指向第三个根节点,依次类推。
树的遍历:
先序遍历:先访问父节点,再访问孩子结点
后序遍历:先访问孩子结点,再访问父节点 (相当于把树转化为二叉树链式存储时候的中序遍历)
森林的遍历:
先序遍历森林:
访问森林中第一棵树的根节点
先序遍历第一棵树中根节点的子树森林
先序遍历除去第一棵树之后剩余的树构成的森林
中序遍历森林:(注意此遍历是指将森林用二叉树的存储方式链式存储(兄弟孩子表示法)时候的遍历规则,它相当于对每一棵树进行后续遍历)
中序遍历森立中第一棵树的根节点的子树森林
访问第一棵树的根节点
中序遍历除去第一棵树之后剩余的树构成的森林
2.二叉树
二叉树的定义:度数为2的有序树
几个特殊的二叉树:
满二叉树:每一层都含有最大数量的结点的二叉树
完全二叉树:除了最下面一层外,每一层都含有最大数量的结点的二叉树,且最下面一层的结点从左到右排列没有空缺的位置
二叉树的存储结构:
顺序存储结构:通常只用顺序存储结构保存完全二叉树,这么做的好处是可以根据数组的index来确定一个结点的孩子
链式存储结构:
/**@数据结构:树->二叉树 **@作者:9761滴 **@存储结构:链表 **/ //本文件中实现了二叉树的 /*1.前 中 后序遍历以及层序遍历 的递归算法和非递归算法 **PreOrder() **InOrder() **PostOrder() **LevelOrder() */ //等操作 #include<cstdio> #include<stack> #include<queue> using namespace std; typedef int ElementType; //二叉树结点的结构体 typedef struct BNode{ ElementType data; BNode *lchild,*rchild; }BNode,*BTree; //线索二叉树结点的结构体 void visit(BTree T){ printf("%d\n",T->data); } //前序遍历,递归实现 void PreOrder(BTree T){ if(T!=NULL){ visit(T); PreOrder(T->lchild); PreOrder(T->rchild); } } //前序遍历,非递归实现 void PreOrder2(BTree T){ stack<BNode*> S; BTree P=T; while(P!=NULL||!S.empty()){ if(P){ visit(P); S.push(P); P=P->lchild; } else{ P=S.top(); S.pop(); P=P->rchild; } } } //中序遍历,递归实现 void InOrder(BTree T){ if(T!=NULL){ InOrder(T->lchild); visit(T); InOrder(T->rchild); } } //中序遍历,非递归实现 void InOrder2(BTree T){ stack<BNode*> S; BTree P=T; while(!S.empty()||P!=NULL){ if(P!=NULL){ S.push(P); P=P->lchild; } else{ P=S.top(); S.pop(); visit(P); P=P->rchild; } } } //后序遍历,递归实现 void PostOrder(BTree T){ if(T!=NULL){ PostOrder(T->lchild); PostOrder(T->rchild); visit(T); } } //后序遍历,非递归实现 void PostOrder2(BTree T){ stack<BNode*> S; BTree P=T; BTree R=NULL; while(P!=NULL||!S.empty()){ if(P!=NULL){ S.push(P); P=P->lchild; } else{ P=S.top(); if(P->rchild==NULL){ visit(P); S.pop(); R=P; P=NULL; } else if(R!=P->rchild){ P=P->rchild; S.push(P); P=P->lchild; } } } } //层序遍历 void LevelOrder(BTree T){ queue<BNode*> Q; Q.push(T); BTree P; while(!Q.empty()){ P=Q.front(); Q.pop(); visit(P); if(P->lchild){ Q.push(P->lchild); } if(P->rchild){ Q.push(P->rchild); } } } int main(){ return 0; }