树的遍历
-
前序遍历
//非递归实现 void preorder(node *tree,int m){ if(!tree)return; stack<node*>s; s.push(tree); while(!s.empty()){ tree=s.top(); s.pop(); cout<<tree->data; for(int i=m-1;i>=0;i--){ if(tree->child[i])s.push(tree->child[i])); } } }
-
层次遍历
//非递归实现 void levorder(node *tree,int m){ if(!tree)return; queue<node*>q; q.push(tree); while(!q.empty()){ tree=q.front(); q.pop(); cout<<tree->data; for(int i=0;i<m;i++){ if(tree->child[i])q.push(tree->child[i]); } } }
-
后序遍历
//非递归实现 void postorder(node *tree,int m){ if(!tree)return; node *stack[N],*p; int mark[N]; int top=-1; stack[++top]=tree; mark[top]=0; while(top>=0){ p=stack[top]; if(mark[top]==0){ mark[top]=1; for(int j=m-1;j>=0;j--){ if(p->child[j]){ stack[++top]=p->child[j]; mark[top]=0; } } } if(mark[top]==1){ cout<<stack[top--]->data; } } }
二叉树和森林的转化
二叉树的遍历
- 前序遍历
//非递归实现
void pre(node*t){
if(!t)return;
stack<node*>s;
s.push(t);
while(!s.empty()){
t=s.top();
s.pop();
cout<<p->data;
if(p->rchild)s.push(p->rchild);
if(p->lchild)s.push(p->lchild);
}
}
-
中序遍历
//非递归实现 void inorder(node*t){ if(!t)return; stack<node*>s; while(t||!s.empty()){ while(t){ s.push(t); t=t->lchild; } if(!s.empty()){ t=s.top();s.pop(); cout<<t->data; t=t->rchild; } } }
-
后序遍历
//非递归实现1 void post(node*t){ node *stack[N],*p; int mark[N]; int top=-1; stack[++top]=t; mark[top]=0; while(top>=0){ if(mark[top]==0){ mark[top]=1; p=stack[top]; if(p->rchild){ stack[++top]=p->rchild; mark[top]=0; } if(p->lchild){ stack[++top]=p->lchild; mark[top]=0; } } if(mark[top]==1)cout<<stack[top--]->data; } } //非递归实现2 双栈 void post(node*t){ s1.push(t); while(!s1.empty()){ p=s1.top(); s1.pop(); s2.push(p); if(p->lchild)s1.push(p->lchild); if(p->rchild)s1.push(p->rchild); } while(!s2.empty()){ p=s2.top();s2.pop(); cout<<p->data; } }
二叉树遍历算法的应用
- 求树的高度
-
空树的高度为-1;
-
只有一个根节点,高度为0;
-
若不空,它的高度等于:
max(左子树深度,右子树深度)+1
int depth(node*t){ if(!t)return -1; if(!t->lchild&&!t->rchild)return 0; return max(depth(t->lchild),depth(t->rchild))+1; }
-
求结点的数量
int count(node*t){ if(!t)return 0; return count(t->lchild)+count(t->rchild)+1 }
-
求叶子结点的个数
-
空树:0
-
只有一个根节点:1
-
有子树:左子树叶子结点个数+右子树叶子结点个数
void countleft(node*t,int&cnt){ if(t){ if(!t->lchild&&!t->rchild)cnt++; countleft(t->lchild,cnt); countleft(t->rchild,cnt); } }
- 复制二叉树
- 判断二叉树是否相等
二叉树的性质
-
如果从0开始计算二叉树的层次,则在第i层最多有 2 i 2^i 2i个结点
-
高度为h的二叉树,最多有 2 h + 1 − 1 2^{h+1}-1 2h+1−1个结点(高度为h则实际上有h+1层)
-
任意一颗二叉树,如果其叶结点有 n 0 n_0 n0个,次数为2的非叶子结点有 n 2 n_2 n2个则有 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1;
设次数为1的结点有 n 1 n_1 n1个,总结点个数为n,总边数为e,则
n = n 0 + n 1 + n 2 n=n_0+n_1+n_2 n=n0+n1+n2
e= 2 n 2 + n 1 = n − 1 2n_2+n_1=n-1 2n2+n1=n−1
所以, n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1
-
具有n(n>0)个结点的完全二叉树的深度为[ l o g 2 n log_2n log2n]
穿线树与穿线排序
-
中序穿线树
设T是一棵二叉树,我们采用标准形式存储这棵二 叉树。对于T中的每个结点k,如果它没有左(或右)子结点, 而k’是k的按中序的前面(或后面)结点,那么置结点k的左
(或右)指针为k’的地址。ltag=1,lchild用来存放“线”,指向的是该结点的按中序的前面结点。
ltag=0,lchild指向真正的左子结点。
rtag=1,rchild用来存放“线”,指向中序的后继。
rtag=0,rchild指向真正的右子结点用一个指针root指向根结点,还用一个指针head指向按中序的最前面一个结点。
无左子结点: t->ltag=1 或 t->lchild =NULL(中序的第一个)
无右子结点: t->rtag=1 或 t-rchild =NULL(中序的最后一个)
-
在穿线树中插入一个结点
// 在给定的穿线树中,找出指针t所指结点的按中序的前面结点 node* pred(node*t){ if(t->ltag==1||t->lchild==NULL)//无子树或中序的第一个 return (t->lchind); }
-
用穿线树进行排序
计算二叉树的数目
-
如果有n个结点,共有多少棵不同(形态的二叉树)
卡特兰树/合法的出栈序列的个数
b n = 1 n + 1 C 2 n n b_n=\frac{1}{n+1}C^{n}_{2n} bn=n+11C2nn