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;
}
// 注意:可以用后序非递归实现本算法,算法思路:借助栈来实现 首先交换左右子树 右子树不为空时将右子树入栈 左子树不为空时指针指向左子树 否则出栈
posted @ 2023-10-17 21:24  yuezi2048  阅读(9)  评论(0编辑  收藏  举报