点击查看代码
#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; //最后返回二叉树根结点地址
}