二叉树的动态实现(使用指针)

点击查看代码
#include<cstdio>
#include<queue>
using namespace std;
#pragma warning(disable:4996) 

//二叉链表结构
struct node { 
	int data; //数据域
	node* lchild; //指向左子树根结点
	node* rchild; //指向右子树根结点
};

node* root = NULL; //在二叉树建树前根结点不存在,因此设为空地址

//新建结点,结点权值为v
node* newNode(int v) { 
	node* Node = new node; //申请新结点的内存
	Node->data = v; //结点权值为v
	Node->lchild = Node->rchild = NULL; //初始状态下没有左右孩子
	return Node; //返回新建结点的地址
}

//二叉树的查找和修改
//查找权值为x的结点,并将权值改为newdata
void search(node* root, int x, int newdata) { 
	if (root == NULL) {	//遇到空结点时返回上一层
		return; 
	}
	if (root->data == x) { //找到权值为x的结点
		root->data = newdata; //将权值改为newdata
	}
	search(root->lchild, x, newdata); //往左子树查找权值为x的结点
	search(root->rchild, x, newdata); //往右子树查找权值为x的结点
}

//二叉树结点的插入,在二叉树中插入一个权值为x的结点
//注意:根结点指针root要使用引用型,因为新建结点后返回的新地址会改变root指向的地址
void insert(node*& root, int x) { 
	if (root == NULL) {	//遇到空结点时表示查找失败,在该位置插入新结点
		root = newNode(x); //调用newNode()函数新建权值为x的结点,将新结点地址赋给root
		return;
	}
	//根据题目给出的二叉树性质,判断权值为x的结点要插在左子树还是右子树
	if (根据题目给出的二叉树性质,权值为x的结点要插在左子树) {
		insert(root->lchild, x); //往左子树查找权值为x的结点
	}
	else {
		insert(root->rchild, x); //往右子树查找权值为x的结点
	}
}

//二叉树的创建
node* Create(int data[], int n) {
	node* root = NULL; //建立二叉树的根结点,初始指向空地址
	for (int i = 0; i < n; i++) {
		insert(root, data[i]); //将data[0]~data[n-1]插入到二叉树中
	}
	return root; //返回根结点地址
}

//二叉树先序遍历:根结点->左子树->右子树
void preorder(node* root) {
	if (root == NULL) {
		return; //到达空结点时,返回上一层
	}
	//访问根结点root,执行相关操作,如输出根结点数据
	printf("%d\n", root->data);
	//访问左子树
	preorder(root->lchild);
	//访问右子树
	preorder(root->rchild);
}

//二叉树中序遍历:左子树->根结点->右子树
void inorder(node* root) {
	if (root == NULL) {
		return; //到达空结点时,返回上一层
	}
	//访问左子树
	inorder(root->lchild);
	//访问根结点root,执行相关操作,如输出根结点数据
	printf("%d\n", root->data);
	//访问右子树
	inorder(root->rchild);
}

//二叉树后序遍历:左子树->右子树->根结点
void postorder(node* root) {
	if (root == NULL) {
		return; //到达空结点时,返回上一层
	}
	//访问左子树
	postorder(root->lchild);
	//访问右子树
	postorder(root->rchild);
	//访问根结点root,执行相关操作,如输出根结点数据
	printf("%d\n", root->data);
}

//二叉树层序遍历:从根结点向下逐层进行遍历,且对同一层的结点按从左至右的顺序进行访问
//注意:队列要存储结点的地址,而不是结点本身,因为队列存储的是数据副本,只有存储结点地址,以后才能根据地址找到真正的结点
void LayerOrder(node* root) {
	queue<node*>q; //定义队列q,要存储结点的地址
	q.push(root); //将根结点地址入队
	while (!q.empty()) { //只要队列q非空就继续遍历
		node* now = q.front(); //用now指针访问当前结点
		q.pop(); //结点出队后要手动删除
		//访问当前结点now,执行相关操作,如输出结点数据
		printf("%d", now->data);
		if (now->lchild != NULL) q.push(now->lchild); //now结点左孩结点非空,则将左孩存入队列q内
		if (now->rchild != NULL) q.push(now->rchild); //now结点右孩结点非空,则将右孩存入队列q内
	}
}

//每个结点增加一个层号标记
struct node1 { 
	int data; //数据域
	int layer; //层号
	node1* lchild; //左孩指针
	node1* rchild; //右孩指针
};

//使用二叉树层序遍历计算每个结点所在的层号(根结点是第1层)
void LayerOrder(node1* root) {
	queue<node1*>q; //定义队列q,要存储结点的地址
	root->layer = 1; //根结点的层号是1
	q.push(root); //将根结点地址入队
	while (!q.empty()) { //只要队列q非空就继续遍历
		node1* now = q.front(); //用now指针访问当前结点
		q.pop(); //结点出队后要手动删除
		//访问当前结点now,执行相关操作,如输出结点数据
		printf("%d", now->data);
		if (now->lchild != NULL) { //now结点左孩结点非空
			now->lchild->layer = now->layer + 1; //左孩结点层号为当前层号加一
			q.push(now->lchild); //则将左孩存入队列q内
		}
		if (now->rchild != NULL) { //now结点右孩结点非空
			now->rchild->layer = now->layer + 1; //右孩结点层号为当前层号加一
			q.push(now->rchild); //则将右孩存入队列q内
		}
	}
}

//给定一棵二叉树的先序遍历序列和中序遍历序列,重建这棵二叉树
int pre[11]; //已知的先序和中序序列,数组下标对应结点编号(从1开始),元素值是结点的权值
int in[11];

//函数返回根结点地址,当前先序序列区间[preL,preR],中序序列区间[inL,inR]
node* create(int preL, int preR, int inL, int inR) {
	if (preL > preR) { //当先序序列左边界大于右边界时
		return NULL; //结束递归,返回一个空地址作为左或右孩结点
	}
	node* root = new node; //新建一个结点,存放当前二叉树的根结点
	root->data = pre[preL]; //当前二叉树的根结点权值是先序序列第1个元素preL的权值
	int k; //中序序列索引
	for (k = inL; k <= inR; k++) { //遍历中序序列[inL,inR]
		if (in[k] == pre[preL]) { //查找中序序列中等于根结点的元素k
			break;
		}
	}
	int numLeft = k - inL; //左子树的结点个数
	//左子树的先序区间[preL+1,preL+numLeft],中序区间[inL,k-1]
	//返回左子树的根结点地址,赋值给root的左指针
	root->lchild = create(preL + 1, preL + numLeft, inL, k - 1);

   	//右子树的先序区间[preL+numLeft+1,preR],中序区间[k+1,inR]
	//返回右子树的根结点地址,赋值给root的右指针
	root->rchild = create(preL + numLeft + 1, preR, k + 1, inR);

	return root; //最后返回二叉树根结点地址
}

posted @ 2022-09-29 23:01  zhaoo_o  阅读(14)  评论(0编辑  收藏  举报