树是n(n>=0)个结点的有限集,n为0时称为空树,对非空树有且仅有一个特定被称为根的结点,其余结点可分为m(m>=0)个互不相交的子集T1,T2,...,Tm,其中每个子集本身又是树,称为子树.
路径长度:路径所经过的边的数目
树的度:该树结点的最大度数.
结点的度:一个结点拥有的子树数
树的高度或深度:树中结点的最大层数
有序树:将树中每个结点的各子树看成从左到右有次序的.
满二叉树
完全二叉树:最下层上的结点都集中在该层最左边的若干位置上.
二叉树
存储结构:指向双亲的指针parent,指向左孩子的指针lchild,数据域data,指向右孩子的指针rchild
class Node{
public:
Node():lchild(NULL),rchild(NULL){};
ElemType data;
class Node *lchild,*rchild;
};
二叉树遍历
前序遍历:访问结点->遍历其左子树->遍历其右子树
void preOrderTraverse_aux(NodePointer p){
if (p) {
std::cout<<p->data;
inOrderTraverse_aux(p->lchild);
inOrderTraverse_aux(p->rchild);
}
}
中序遍历:遍历其左子树->访问结点->遍历其右子树
后序遍历:遍历其右子树->遍历其左子树->访问结点
求二叉树的叶子树
int countLeaf_aux(NodePointer p){
int num;
static int i = 0;
if (p) {
if (!p -> lchild && !p -> rchild) {
++i;
}
countLeaf_aux(p->lchild);
countLeaf_aux(p->rchild);
}
if (p == root) {
num = i ;
i = 0;
}
return num;
}
求二叉树的结点数
int countNode_aux(NodePointer p){
int num;
static int i = 0;
if (p) {
i++;
countNode_aux(p->lchild);
countNode_aux(p->rchild);
}
if (p == root) {
num = i;
i = 0;
}
return num;
}
求深度
int depth_aux(NodePointer p){
int lDep,rDep;
if (!p) {
return 0;
}else{
lDep = depth_aux(p->lchild);
rDep = depth_aux(p->rchild);
return lDep>rDep?lDep:rDep + 1;
}
}
void layOrderTraverse_aux(){
NodePointer p;
SqQueue<NodePointer> Q;
if (root != NULL) {
Q.enQueue(root);//如果当前二叉树不为空,则让根指针进入待遍历结点的指针队列
}
while (!Q.isEmpty) {
Q.deQueue(p);
std::cout<<p->data;
if (p->lchild) {
Q.enQueue(p->lchild);//如果有左孩子,则把左孩子进队列
}
if(p->rchild){
Q.enQueue(p->rchild);//如果有右孩子,则把左孩子进队列
}
}
}
中序穿线二叉树
存放指向结点在某种遍历次序下的前驱和后继结点的指针,这种附加的指针称为"线索",加上线索的二叉链表称为线索链表,相应的二叉树称为穿线二叉树.解决了二叉链表无法直接找到在某种遍历序列中得前驱和后继结点的问题.
存储结构
左指针标记ltag,左指针域lchild,结点数据域data,右指针域rchild,右指针标记rtag
中序遍历中序穿线二叉树
void inOrderTraverse_ThreadTree(){
ThreadTNPointer p = root;
while (p) {
//先沿着其左子树的左指针向下滑动,直到某结点有左线索为止
while (p->ltag == LINK) {
p = p->lchild;
}
std::count<<p->data;
//如果该结点有右线索,则沿着右线索一直往上爬,访问右线索上的每一个结点
//直到某结点不再有右线索,而有右指针为止.
while (p->rtag == THREAD && p->rchild) {
p = p->rchild;
std::count<<p->data;
}
p = p->rchild;
}
}
查深度
int depth(ThreadTNPointer p){
int lDep,rDep;
if (!p) {
return 0;
}else{
if (p->ltag == LINK) {//如果指针p不为空且所指结点有左指针
lDep = depth(p->lchild);//则用左指针自递归求其左子树的深度
}else{//如果有左线索,则其左子树的深度为0
lDep = 0;
}
if (p->rtag == LINK) {//如果指针p不为空且所指结点有右指针
rDep = depth(p->rchild);//则用右指针自递归求右子树的深度
}else{//如果有右线索
rDep = 0;//则右子树的深度为0
}
return lDep>rDep?lDep:rDep + 1;
}
}
找指定点
bool searchNode(ElemType key,ThreadTNPointer &p){
p = root;
while (p) {
while (p->ltag == LINK) {
p = p->lchild;
}
if (p->data == key) {
return true;
}
//如果该结点有右线索,则沿着右线索一直往上爬,直到某结点出现右指针为止
//判断右线索上每个的数据是否等于值key
while (p->rtag == THREAD && p->rchild) {
p = p->rchild;
if (p->data == key) {
return true;
}
}
p = p->rchild;
}
return false;
}
bool searchNextNode(ElemType key,ElemType& next){
ThreadTNPointer p;
if (searchNode(key, p)) {
if (p->rtag == THREAD) {
if (!p->rchild) {
return false;
}else{
next = p->rchild->data;
}
}else{
//如果指针p所指结点有右指针,则进入其右子树,
//在一直沿着左指针往下滑动,直到某个结点不再有左指针,而有左线索为止,
//则该结点即为指定结点中序遍历的后继.
p = p->rchild;
while (p->ltag == LINK) {
p = p->lchild;
}
next = p->data;
}
}
return true;
}
查前驱
bool searchPriorNode(ElemType key,ElemType& prior){
ThreadTNPointer p;
if (searchNode(key, p)) {
if (p->ltag == THREAD) {
if (!p->lchild) { //如果是中序遍历的第一个结点,则无前驱
return false;
}else{
prior = p->lchild->data;//则左线索即为指定结点中序遍历的前驱
}
}else{
//如果指针p所指结点有左指针,则进入其左子树,
//在一直沿着右指针往下滑动,直到某个结点不再有右指针,而有右线索为止,
//则该结点即为指定结点中序遍历的前驱.
p = p->lchild;
while (p->rtag == LINK) {
p = p->rchild;
}
prior = p->data;
}
}
return true;
}