17道树的遍历代码练习
1.查找树中的最大结点(前序visit)
// 1.查找树中的最大结点
int maxn = -32767;
int findMax(BiTree T){
if(T != NULL){
if(T->data > Maxn) maxn = T->data;
findMax(T->lchild);
findMax(T->rchild);
}
}
2.输出值为x的所有结点的兄弟值(前序vis)
// 2.给出孩子-兄弟二叉链表,输出值为x的所有结点的兄弟值
void printSibling(CSTree T, int x){
if(T != NULL){
CSNode *p = T->firstchild; // 下一个孩子
CSNode *q = T->nextsibling; // 下一个兄弟
if(T->data == x){
while(q){
printf("%d", q->data);
q = q->nextsibling;
}
}
printSibling(T->firstchild,x);
printSibling(T->nextsibling, x);
}
}
3.输出树的路径长度之和(代参前序vis)
// 3. 输出树的路径长度之和
int length = 0;
// 调用该函数时 depth初值为1
void getLength(BiTree T, int depth){
if(T != NULL){
length += (depth - 1);
getLength(T->lchild, depth + 1);
getLength(T->rchild, depth + 1);
}
}
4.孩子兄弟序列(CS层序)
// 4.输出(1,2) (1,3) (2,4) 孩子兄弟序列
void printCS(CSTree* T){
queue<CSTree*> q; // q是临时存放结点的队列
q.push(T);
while(q.empty()){
CSTree node1 = q.top();
q.pop();
CSTree node2 = node1->firstchild;
// 请类比于二叉树分别对lchild 和 rchild 进行入队操作 这里是进行了顺带输出
while(node2){
printf("(%d,%d)", node1->data, node2->data);
q.push(node2);
node2 = node2->nextsibling;
}
}
}
5.孩子兄弟表示法中统计树的高度(后序)
注意区分二叉树,这里的孩子兄弟表示法子女需要高度+1而兄弟不用,而普通的二叉树,可以看成是左右两个子女,都是要加1的
// 5.在孩子兄弟表示法中统计树的高度
int getCSDepth(CSTree T){
if(T == NULL) return 0; // 空结点的高度标记为0
else{
int h1 = getCSDepth(T->firstchild); // 子女的高度
int h2 = getCSDepth(T->nextsibling); // 兄弟的高度
return max(h1 + 1, h2); // 取子女的高度+1 和 兄弟的高度(注意类比二叉树中都是要+1)
}
}
6.判断是否为完全二叉树(层序 判空思路)
// 6.判断是否为完全二叉树(核心思想:层序遍历 + 空结点后面不能有非空结点)
bool isComplete(BiTree T){
if(T == NULL) return true; // 空树是完全二叉树
queue<BiTree*> q; // 建立用以存储结点的队列
q.push(T->data); // 初始插入根结点
BiTree p;
// 层序遍历
while(!isEmpty(Q)){
p = Q.front(), Q.pop(); // 出列队首,并处理该元素
// 非空结点则插入左右子树
if(p){
q.push(T->lchild);
q.push(T->rchild);
}
// 空结点要判断该层后序有无结点
else{
while(!isEmpty(Q)){
p = Q.front(), Q.pop();
if(p) return false; // 存在非空结点 则不是完全二叉树
}
}
}
return true;
}
7.判断是否为二叉排序树(中序 序列递增特性)
// 7. 判断是否为二叉排序树(中序遍历+保留前继pre)
// 由于中序遍历是左中右,最终返回右子树的结果从而代表整个遍历序列是否满足递增
int pre = -32767;
int isBST(BiTree T){
int l, r; // 左子树 右子树是否为二叉排序树
if(T == NULL) return 1; // 空树是二叉排序树
else{
l = isBST(T->lchild);
if(l == 0 || T->data < pre) return 0; // 如果当前结点比前继结点小或者左子树不是二叉排序树,那么就不是二叉排序树
pre = T->data; // 保留前继结点
r = isBST(T->rchild);
return r;
}
}
8.统计叶子结点个数(前序+指针保留)
// 7. 判断是否为二叉排序树(中序遍历+保留前继pre)
// 由于中序遍历是左中右,最终返回右子树的结果从而代表整个遍历序列是否满足递增
int pre = -32767;
int isBST(BiTree T){
int l, r; // 左子树 右子树是否为二叉排序树
if(T == NULL) return 1; // 空树是二叉排序树
else{
l = isBST(T->lchild);
if(l == 0 || T->data < pre) return 0; // 如果当前结点比前继结点小或者左子树不是二叉排序树,那么就不是二叉排序树
pre = T->data; // 保留前继结点
r = isBST(T->rchild);
return r;
}
}
// 注意,当然也有后序版本的,见12题
9.查找二叉排序树值为key的地址(BST查找)
// 9. 查找二叉排序树值为key的地址
BiTree* findBST(BiTree T, int key){
if(T == NULL) return NULL;
else{
if(key == T->data) return T;
elseif(key < T->data) return findBST(T->lchild, key); // 比结点小的往左子树找
else return (T->rchild); // 比key大的往右子树找
}
}
10.查找度为1结点(后序递推)
// 10.以查找度为1结点为例,给出统计满足条件的结点 后序递推版
bool judege(BiTree T){
return T->lchild == NULL && T->rchild != NULL || T->lchild != NULL && T->rchild == NULL;
}
int getNum(BiTree T){
if(judge(T)) return 1 + getNum(T->lchild) + getNum(T->rchild);
else return getNum(T->lchild) + getNum(T->rchild);
}
11.中序二叉线索树后继(pre指针保留)
// 11.找出中序二叉搜索树p结点后序结点(注意保留技术)
BiTree* findNext(BiTNode* p){
// rtag 为1 具有线索直接访问右孩子
if(p->rtag == 1) return p->rchild;
// rtag 为0 说明有非空右孩子 访问右子树中最左的结点
BiTNode *q = p->rchild;
BiTNode *pre;
while(q != NULL) pre=q, q=q->lchild;
return pre;
// 标答写法
// for(q = p->rchild; p->ltag == 0; p= p->lchild) pre = p;
// return pre;
}
12.二叉树结点和度为1个数统计(后序递推)
// 12.二叉树结点个数统计, 统计度为1的个数
int getCnt(BiTree T){
if(T == NULL) return 0;
return 1 + getCnt(T->lchild) + getCnt(T->rchild); // 采用后序遍历实现
}
int getCnt_1(BiTree T){
if(T == NULL) return 0;
else{
if(T->lchild == NULL && T->rchild !=NULL || T->lchild != NULL && T->rchild == NULL){
return 1 + getCnt_1(T->lchild) + getCnt_1(T->rchild);
}
else{
return getCnt_1(T->lchild) + getCnt_1(T->rchild);
}
}
}
所以,叶子结点,度为1的结点,度为2的结点,都可以用此思路,,
13.二叉树后序遍历线索化(后序+前后线索)
BiTNode* pre;
void postThread(BiTree root){
if(root != NULL){
postThread(T->lchild);
postThread(T->rchild);
// 当前结点的前驱线索化
if(T->lchild == NULL){
T->lchild = pre;
T->ltag = 1;
}
// pre结点的后驱线索化
else if (pre->rchild == NULL && pre != NULL){
pre->rchild = root;
pre->rtag = 1;
}
pre = T; // 记录上次访问的结点
}
}
14.建立一颗二叉排序树(0结尾) 前序
int createTree(BiTree *T, int key){
if(T == NULL){ // 空结点建立新结点
T = (BiTree)malloc(sizeof(BiTNode));
T->data = key;
T->lchild = T->rchild =NULL;
return OK; // 插入成功
}
else{ // 当前结点为非空
if(key < T->data) createTree(T->lchild, key); // key小于根结点,往左子树递归
else if(key > T->data) createTree(T->rchild, key); // key大于根结点,往右子树递归
else return Error; // 相同元素不合法,插入失败
}
}
void BST_Create(){
int key;
T = (BiTree)malloc(sizeof(BiTNode));
while(true){
cin>>key;
if(key == 0) break;
createTree(T, key);
}
}
15.从大到小输出二叉排序树(逆中序)
// 15.从大到小输出二叉排序树
void printBST(BiTree T){
if(T == NULL) return ;
else{ // 进行逆中序遍历
printBST(T->rchild);
printf("%d ", T->data);
printf(T->lchild);
}
}
// 备注:标答给的答案是按照标准中序遍历,只是把结果存入栈了,遍历完之后一个个出栈就是逆序
16.前序遍历树的后继结点(前序线索)
// 16.前序遍历树的后继结点
BiTNode* findNext2(BiTNode p){
if(p->ltag == 0){ // p的左子树存在那么后继结点就是左子树
return p->lchild;
}
else{ // p左子树不存在那么后继结点r->tag==0时是右子树 r->tag==1时就是右子树的线索,合在一起即为r->lchild
return p->rchild;
}
}
17.二叉树左右子树互换(前序遍历)
// 17.二叉树左右子树互换
BiTNode* invertTree(BiTree* T){
if(T==NULL) return NULL;
// 递归写法,前序遍历,注意,由于算法交换左右子树的特殊性,万万不能中序遍历
BiTNode *p = T->lchild;
BiTNode *q = T->rchild;
T->lchild = q;
T->rchild = p;
}
// 注意:可以用后序非递归实现本算法,算法思路:借助栈来实现 首先交换左右子树 右子树不为空时将右子树入栈 左子树不为空时指针指向左子树 否则出栈