具体思想参照注释
#include<bits/stdc++.h>
using namespace std;
#define maxn 100
//*********孩子兄弟树*********
typedef struct CSNode{
int data;
CSNode *firstchild;
CSNode *nextsibling;
}* CSTree;
//第一种递归建立孩子兄弟树
void SetupCSTree(CSTree &head)
{
int a,b;
CSTree child,brother;
printf("请输入%d的孩子(-1表示空):",head->data);
scanf("%d",&a);
printf("请输入%d的兄弟(-1表示空):",head->data);
scanf("%d",&b);
if(a == -1)
head->firstchild = NULL;
else
{
child = (CSTree)malloc(sizeof(CSNode));
child->data = a;
head->firstchild = child;
SetupCSTree(head->firstchild);
}
if(b == -1)
head->nextsibling = NULL;
else
{
brother = (CSTree)malloc(sizeof(CSNode));
brother->data = b;
head->nextsibling = brother;
SetupCSTree(head->nextsibling);
}
}
void Init_CSTree(CSTree &tree)
{
int root;
printf("请输入根节点:");
scanf("%d",&root);
tree = (CSTree)malloc(sizeof(CSNode));
tree->data = root;
tree->firstchild = NULL;
tree->nextsibling = NULL;
SetupCSTree(tree);
}
/*
//第二种递归建立孩子兄弟树的方式
vector<vector<int> > cstree(maxn);//用来存储孩子兄弟树,然后再链式建树
int fa[maxn];//用来找某个节点的父亲节点
CSTree CreateCSTree(int u, int pos)
{
// 这个函数比较NB,膜拜王大师,所以我注释详细一些
// u代表当前节点的值 pos代表该节点在它的父亲节点的存放位置
// 首先递归过程是首先递归到叶子结点,赋值,返回的过程判断该节点是否有兄弟,
// 有的话就去搞它的兄弟节点的所有信息 最终构建成功
CSTree csnode = (CSTree)malloc(sizeof(CSNode)); //开辟空间
if (!cstree[u].empty()) csnode->firstchild = CreateCSTree(cstree[u][0], 0);//搞第一个儿子
else csnode->firstchild = NULL;
//有兄弟,先去搞兄弟
if (u != 1 && pos != cstree[fa[u]].size()-1) csnode->nextsibling = CreateCSTree(cstree[fa[u]][pos+1],pos+1);
else csnode->nextsibling = NULL;
csnode->data = u;
return csnode;
}
//构建孩子兄弟树 -1表示叶子结束 -2表示根节点结束 规定 根必须从1开始
//一切为了简化操作 节点值不要重复
//比如 先输入根1 然后输入1的孩子 2 3 4 输入-1 换下一个根节点
// 输入2 输入2的孩子5 输入-1 退出根输入-2
void SetupCSTree(CSTree &head)
{
char ch;
int root = 0,leaf = 0;
while(root != -2){
printf("请输入根节点(-2表示结束):");
scanf("%d",&root);
ch = getchar();
if(root == -2)
break;
while(leaf != -1)
{
printf("请输入%d的孩子节点(-1表示结束):",root);
scanf("%d",&leaf);
ch = getchar();
if(leaf == -1)
break;
cstree[root].push_back(leaf);
fa[leaf] = root;
}
leaf = 0;
}
head = CreateCSTree(1,0);
}
*/
//************真题分界线****************
int cstree_high = 1; //孩子兄弟树的高度
int num = 0;//最后一代的个数
void DFS1(CSTree tree,int high)
{
if(tree == NULL)
return;
if(tree->nextsibling != NULL)
{
cstree_high = max(cstree_high,high); //兄弟 高度不能变
DFS1(tree->nextsibling,high);
}
if(tree->firstchild != NULL)//孩子节点不为空 未访问过
{
cstree_high = max(cstree_high,high+1);//高度加一 去最大值
DFS1(tree->firstchild,high+1);
}
}
void DFS2(CSTree tree,int high)
{
if(tree == NULL)
return;
else if(high == cstree_high)
{
num++;
printf("%d ",tree->data);
}
if(tree->nextsibling != NULL)
{
DFS2(tree->nextsibling,high);
}
if(tree->firstchild != NULL)//孩子节点不为空 未访问过
{
DFS2(tree->firstchild,high+1);
}
}
void HomeTree(CSTree tree)// 2014年829和922真题 求共有多少代人,最后一代的人数并输出
{
/*
算法思想:第一次dfs搜索,找出共有多少代。
注意的是左边是孩子节点,代数要加一,右边是兄弟节点,代数不变 。
第二次搜索,找到最后一代,输出并计数
*/
DFS1(tree,1);//第一次搜索 找出共有多少代人
printf("家谱中共有%d代\n",cstree_high);
DFS2(tree,1);//总结最后一代人数和输出最后一代
printf("\n最后一代人个数是%d",num);
}
int CSTree_width(CSTree tree) //2012年922真题 求孩子兄弟树的宽度
{
//算法思想: 层次遍历,每一层找出最大宽度
if(tree == NULL)// 为空返回0
return 0;
int width = 1;
int width_tmp = 0;
queue<CSTree > Q,Assist; //Q队列存孩子 Assist队列存兄弟
CSTree tmp; //队列头
Q.push(tree);
while(!Q.empty())
{
width_tmp = 0;
int length = Q.size();
width_tmp = length;
while(length--) //所有兄弟节点入队
{
tmp = Q.front();
if(tmp->firstchild != NULL)
{
Q.push(tmp->firstchild);
}
while(tmp->nextsibling != NULL)
{
Assist.push(tmp->nextsibling);
tmp = tmp->nextsibling;
}
Q.pop();
}
width_tmp += Assist.size(); //该层的宽度
//清空辅助队列Assist
while(!Assist.empty())
{
tmp = Assist.front();
if(tmp->firstchild != NULL)
Q.push(tmp->firstchild);
Assist.pop();
}
width = max(width,width_tmp);
}
return width;
}
//*******二叉树分界线**************
// 二叉树的节点值是int类型 -1表示该节点为空
typedef struct BinaryTree{ // 孩子表示
int val;
BinaryTree *left;
BinaryTree *right;
}* Tree;
void SetupTree(Tree &tree) //构建一棵二叉树
{
int ch;
char c;
scanf("%d",&ch);
c = getchar();//必须清除换行符
if(ch == -1)
tree = NULL;
else
{
tree = (Tree)malloc(sizeof(BinaryTree));
tree->val = ch;
printf("输入%d的左子节点:", ch);
SetupTree(tree->left);
printf("输入%d的右子节点:", ch);
SetupTree(tree->right);
}
}
Tree init_tree(vector<int > &nums,int l,int r) // 递归建立平衡二叉树,根节点就是中间节点
{
Tree root = (Tree)malloc(sizeof(BinaryTree));
if(l <= r)
{
int mid = l + (r-l)/2;
root->val = nums[mid];
root->left = init_tree(nums,l,mid-1);
root->right = init_tree(nums,mid+1,r);
}
else
return NULL;
return root;
}
void SetupBinarySortTree(Tree &tree)// 给一个有序数组,建立成二叉排序树
{
int n;
printf("请输入数组元素的个数:");
scanf("%d",&n);
vector<int > array(n);
for(int i = 0;i < n;i++)
scanf("%d",&array[i]);
sort(array.begin(),array.end()); //数组排序
if(array.size() == 0) { tree = NULL; return; }
tree = init_tree(array,0,array.size()-1); //递归建树
}
bool DestroyTree(Tree &tree) //销毁一颗树
{
if(tree != NULL)
{
DestroyTree(tree->left);
DestroyTree(tree->right);
free(tree);
tree = NULL; //这一步不可少,不然指针浮空 不是自动指向NULL
}
return true;
}
void Recursive_Preorder(Tree tree)//递归先序
{
if(tree != NULL)
{
printf("%d ",tree->val);
Recursive_Preorder(tree->left);
Recursive_Preorder(tree->right);
}
}
void Recursive_Inorder(Tree tree)//递归中序
{
if(tree != NULL)
{
Recursive_Inorder(tree->left);
printf("%d ",tree->val);
Recursive_Inorder(tree->right);
}
}
void Recursive_Postorder(Tree tree)//递归后序
{
if(tree != NULL)
{
Recursive_Postorder(tree->left);
Recursive_Postorder(tree->right);
printf("%d ",tree->val);
}
}
int Recursive_TreeHigh(Tree tree)//递归求树的高度
{
int high = 0;
if(tree == NULL)
high = 0;
else
high = max(Recursive_TreeHigh(tree->left),Recursive_TreeHigh(tree->right) ) + 1;
return high;
}
int TreeHigh(Tree tree)//2013年829和922真题 非递归求树的高度
{
/*
算法思想,层次遍历,用队列存储
*/
if(tree == NULL)
return 0;
queue<pair<Tree,int> > Q;//定义一个队列 队列元素是树的节点和它的高度 用pair组合
pair<Tree,int> tmp_tree;//临时节点
Q.push(make_pair(tree,1));
int high = 1;//结果高度
while(!Q.empty())//队列不为空
{
tmp_tree = Q.front();//取出队列头结点
if(tmp_tree.first->left != NULL)
{
Q.push(make_pair(tmp_tree.first->left,tmp_tree.second+1)); //左子树入队 高度+1
}
if(tmp_tree.first->right != NULL)
{
Q.push(make_pair(tmp_tree.first->right,tmp_tree.second+1));//右子树入队 高度+1
}
high = max(high,tmp_tree.second);
Q.pop();
}
return high;
//不会用STL的pair的 换一个写法
/*
思想:用一个变量控制入队的每一层的个数 然后根据这个控制出队的数量
if(tree == NULL)
return 0;
queue<Tree > Q;
Tree tmp; //表示队列头
Q.push(tree);
int high = 0; //高度
int queue_size = 0; //用来控制一个队列中如何表示一层的元素
while(!Q.empty())
{
high++; //每次开始都是下一层节点
queue_size = Q.size(); //求出当前队列元素个数
while(queue_size--) //循环使队列中当前层节点清空 加入下一层节点
{
tmp = Q.front();
if(tmp->left != NULL)
{
Q.push(tmp->left);
}
if(tmp->right != NULL)
{
Q.push(tmp->right);
}
Q.pop();
}
}
return high;
*/
}
void LongestPath_first(Tree tree) //2015年829和922真题 输出树的最长路径
{
/*
算法思想:题目没要求时间空间 所以暴力求解
思路:写一个求树的深度函数 每次找最高的分支
*/
if(tree != NULL)
{
printf("%d ",tree->val);
int left = Recursive_TreeHigh(tree->left);
int right = Recursive_TreeHigh(tree->right);
if(left > right)
LongestPath_first(tree->left);
else
LongestPath_first(tree->right);
}
}
bool Complete_BinaryTree(Tree tree)//2016年829和922真题 判断是否是完全二叉树
{
/*
如果树为空,则直接返回错
如果树不为空:层序遍历二叉树
如果一个结点左右孩子都不为空,则pop该节点,将其左右孩子入队列;
如果遇到一个结点,左孩子为空,右孩子不为空,则该树一定不是完全二叉树;
如果遇到一个结点,左孩子不为空,右孩子为空;或者左右孩子都为空;
则该节点之后的队列中的结点都为叶子节点;
该树才是完全二叉树,否则就不是完全二叉树;
*/
if(tree == NULL)//树为空 不成立
return false;
bool flag = false; //用于判断叶子结点
queue<Tree > Q;//队列
Tree tmp; //用于保存队头
Q.push(tree);
while(!Q.empty())
{
tmp = Q.front();
if(tmp->left && tmp->right)//左右不为空
{
Q.pop();
Q.push(tmp->left);
Q.push(tmp->right);//左右子树入队
}
if(tmp->left == NULL && tmp->right != NULL) //左空右不空 必不是完全二叉树
return false;
//左不空右空 或者 左右全空 表示后面全是叶子结点,否则必不是完全二叉树
if( (tmp->left != NULL && tmp->right == NULL) || (tmp->left == NULL && tmp->right == NULL))
{
Q.pop();
while(!Q.empty())
{
tmp = Q.front();
if(tmp->left != NULL || tmp->right != NULL)//不是叶子节点 不是完全二叉树
return false;
Q.pop();
}
return true; //队列为空 全是叶子节点,则是完全二叉树
}
}
return true;
}
int TwoElem() //2018年829和922真题 判断两个元素和树中元素的关系
{
Tree tree;
printf("请输入根节点:");
SetupTree(tree);
int a,b;
int high_a = 0;
int high_b = 0;
scanf("%d",&a);
scanf("%d",&b); //输入两个整数
if(tree == NULL)
return -2;
queue<pair<Tree,int> > Q;
pair<Tree,int> tmp; //保存队头结点
Q.push(make_pair(tree,1));
while(!Q.empty())
{
tmp = Q.front();
if(tmp.first->val == a)
high_a = tmp.second;
if(tmp.first->val == b)
high_b = tmp.second;
if(tmp.first->left != NULL)
Q.push(make_pair(tmp.first->left,tmp.second+1));
if(tmp.first->right != NULL)
Q.push(make_pair(tmp.first->right,tmp.second+1));
Q.pop();
}
if(high_a == 0 && high_b == 0) //都没找到
return -2;
if(high_a != 0 && high_b != 0) //都找到了
return abs(high_a-high_b);
else //找到一个
return -1;
}
void Delete_X(Tree &tree,int x) //先序遍历 删除以x为根的子树
{
if(tree != NULL)
{
if(tree->val == x)
{
DestroyTree(tree);
return ; //这一句不可少
}
Delete_X(tree->left,x);
Delete_X(tree->right,x);
}
}
void Delete_elem()//2017年922真题 对于给定的值x 删除以x为根的子树
{
int x;
Tree tree;
printf("请输入根节点:");
SetupTree(tree);
printf("请输入值x:");
scanf("%d",&x);
printf("输出未删除%d先序遍历的结果:\n",x);
Recursive_Preorder(tree);
Delete_X(tree,x); //建好树 调用删除函数
printf("输出删除%d后先序遍历的结果:\n",x);
Recursive_Preorder(tree);
}
Tree Lower_boundTree() //2012年922真题 在平衡二叉树中找到小于x且最接近x的节点返回指针
{
//算法思想 如果当前节点大于x,去左子树找,如果小于x,则需要到右子树去找
// 如果右子树的值大于x说明当前节点就是最接近x且小于x,否当前节点跳到右子树
int x;
Tree tree;
SetupBinarySortTree(tree);
printf("请输入查找到值x:");
scanf("%d",&x);
if(tree == NULL)//树为空 返回空
return NULL;
Tree treenode = tree;
while(treenode != NULL)
{
if(treenode->val >= x) //当前节点大于x
{
if(treenode->left != NULL)
treenode = treenode->left; //到左子树
else
break; //不存在 返回空
}
else if(treenode->val < x) //注意 不要直接else 因为不能找到等于x的
{
if(treenode->right != NULL)
{
if(treenode->right->val > x) //右子树节点大于x 则返回当前节点
return treenode;
else if(treenode->right->val < x) //继续向右搜索
treenode = treenode->right;
}
}
}
return NULL;
}
int main()
{
//Tree tree;
//printf("请输入根节点:");
//SetupTree(tree);
//Recursive_Preorder(tree);
//Recursive_Inorder(tree);
//Recursive_Postorder(tree);
//Recursive_TreeHigh(tree);
//printf("%d",TreeHigh(tree));
//LongestPath_first(tree);
//cout<<Complete_BinaryTree(tree)<<endl;
/* CSTree tree;
SetupCSTree(tree);
HomeTree(tree);*/
// printf("%d",TwoElem() );
//Delete_elem();
//SetupBinarySortTree(tree);
//tree = Lower_boundTree();
//if(tree)
// printf("%d\n",tree->val);
//else
// printf("-1\n");
CSTree tree;
Init_CSTree(tree);
printf("%d\n",CSTree_width(tree));
return 0;
}