icoding的数据结构并没有一个测试代码,其都是直接编写一个函数的形式,因此很难知道自己的实际输出是什么。针对部分题目,我编写了一系列测试代码以供大家进行数据输出的测试。
bool path(BiTNode* root, BiTNode* node, Stack* s){ //TODO } BiTNode * nearest_ancestor(BiTree root, BiTNode *p, BiTNode *q){ //TODO }
请将您的函数代码复制到上述函数中,然后修改main函数的相关内容,完成测试样例的输入
注意:icoding代码以int为数据类型,我们这里以字母为数据
打印树的代码源程序来自 打印树源程序
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<string.h>
//二叉树的创建
#define Stack_Size 50
typedef char DataType;
typedef struct Node{
DataType data;
struct Node* left;
struct Node* right;
}BiTNode, *BiTree;
typedef BiTNode* ElemType;
typedef BiTNode* P_Node;
typedef struct{
ElemType elem[Stack_Size];
int top;
}Stack;
int width,height;//打印需要用到的
void visit_node(BiTNode *node){
printf("%c ",node->data);
}
void init_stack(Stack *S) // 初始化栈
{
S->top = -1;
}
bool push(Stack* S, ElemType x) //x 入栈
{
if (S->top == Stack_Size - 1)
return false;
S->top++;
S->elem[S->top] = x;
return true;
}
bool pop(Stack* S, ElemType *px) //出栈,元素保存到px所指的单元,函数返回true,栈为空时返回 false
{
if (S->top == -1)
return false;
*px = S->elem[S->top];
S->top--;
return true;
}
bool top(Stack* S, ElemType *px) //获取栈顶元素,将其保存到px所指的单元,函数返回true,栈满时返回 false
{
if (S->top == -1)
return false;
*px = S->elem[S->top];
return true;
}
bool is_empty(Stack* S) // 栈为空时返回 true,否则返回 false
{
if (S->top == -1)
return true;
return false;
}
//创建树,将输入的字符串以先序的形式存入二叉树
BiTree _CreateByStr(char *nodes, int *i) {
//定位串处理完了
if (nodes[*i] == '\0') return NULL;
//遇到了定位串中的'.',这表明这颗子树是空树
if (nodes[*i] == '.') {
++ *i;
return NULL;
}
//生成新节点,填充数据
BiTree root = (BiTree)malloc(sizeof(BiTNode)); //生成一个新结点
//找到字母标签对应的对照表项,并赋值给data域
root->data = nodes[*i];
//每消费了一个字符,下标*i要后移
++ *i;
//递归生成子树
root->left = _CreateByStr(nodes, i); //生成左子树
root->right = _CreateByStr(nodes, i); //生成右子树
return root;
}
//求深度
int DeepTree(P_Node T)
{
if(!T)
{
return 0;
}
return DeepTree(T->left)>DeepTree(T->right)?DeepTree(T->left)+1:DeepTree(T->right)+1;
//关键代码:如果该节点的左子树深度大于右子树则将左子树的深度加一返回,这个返回值便是以该节点做根节点的树的深度,右子树深度大时则相反
}
//T为二叉树的根节点,a是数组的起始地址,i,j是当前节点在数组中的位置
//如果节点有孩子,其孩子的j坐标为 j±(height-i+1)/2
void fillArray(P_Node T,char *a,int i, int j)
{
int ti,tj;
if(T) //如果该位置有节点
{
*(a+(i*width)+j) = T->data; //向数组该点填入字符
if(T->left) //有左右孩子给对应的连接线,左右孩子的值在下一层递归赋
{
//将该点与其左孩子之间的连线全部填上'/'
for(ti=i+1,tj=j-1;tj>j-(height-i+1)/2;tj--)
{
*(a+((ti)*width)+tj) = -1;
ti++;
}
}
if(T->right)
{
for(ti=i+1,tj=j+1;tj<j+(height-i+1)/2;tj++)
{
*(a+((ti)*width)+tj) = 1;
ti++;
}
}
//经过循环,ti恰好指到其孩子所在的层
fillArray(T->left, a, ti, j-(height-i+1)/2);
fillArray(T->right, a, ti, j+(height-i+1)/2);
}
}
void printBiTree(P_Node T,char search_node)
{
int i,j;
int n = DeepTree(T); //计算出深度n
//在计算机中数据以二进制形式存储,所以一个数据左移1位就相当于乘以2的1次方
width = (2<<n)-3; // 2^(n+1)-3
height = (2<<(n-1))-1; // 2^n-1
char *a = (char *)malloc(sizeof(char) * (width*height)); // 申请空间
// 空间初始化为0
for(i=0;i<height;i++)
{
for(j=0;j<width;j++)
{
*(a+(i*width)+j) = 0;
}
}
//调用之前定义好的函数,填充打印数组
fillArray(T, a, 0, (width-1)/2);
//根据打印数组的内容来实现打印
for(i=0;i<height;i++)
{
for(j=0;j<width;j++)
{
if(*(a+(i*width)+j) == -1)
{
printf("/");
}else if(*(a+(i*width)+j) == 1)
{
printf("\\");
}else if(*(a+(i*width)+j) == 0)
{
printf(" ");
}else
{
if(search_node==*(a+(i*width)+j)){
printf("*%c", *(a+(i*width)+j));
}
else{
printf("%c", *(a+(i*width)+j));
}
}
}
printf("\n");
}
}
//查找节点
P_Node Search(P_Node T, char c)
{
if(!T)
{
return NULL;
}
if(T->data == c)
{
return T;
}
P_Node p = Search(T->left, c);
if(p)
{
return p;
}
p = Search(T->right, c);
if(p)
{
return p;
}
return NULL;
}
void printPreOrder(P_Node T,char search_node){
if(T){
if(search_node==T->data){
printf("[%c]",T->data);
}
else{
printf("%c",T->data);
}
printPreOrder(T->left,search_node);
printPreOrder(T->right,search_node);
}
}
// /以上为辅助函数
bool path(BiTNode* root, BiTNode* node, Stack* s){
//TODO
}
BiTNode * nearest_ancestor(BiTree root, BiTNode *p, BiTNode *q){
//TODO
}
int main(){
///--------以 下 内 容 可 以 修 改 ----------------
char nodes[] = "ABC..D..EF..GH..";
//这是树的定位串,采用先序排列,每个节点的左右孩子用'.'分隔,空节点用'.'代替
//”.”表示空节点,即左/右孩子不存在
//这里提供了一些树的先序定位串
//1. ABC..DE..GH..F... ( 图大,不便打印)
//2. ABC...DE.F.. (图小,可以打印)
//3. ABCD....EF..G... (图小,可以打印)
//4. ABCD.E..F..G... (图大,不便打印)
//5. AB.CD.E..F..G...(图小)
//6. ABC..D..EF..GH..(图小)
//错误的使用“.”可能造成无法打印或者输出图形过于大
int print=3;//是否打印树,0:不打印,1:打印图形,2:打印先序遍历,3:两者都打印。
char search_node='C';//路径,要查找的节点(字母)
//无论是否运行路径函数,都需要指定一个path的待寻找的节点,不能不写。
bool flag=true;//是否进行共同祖先题目的运行?
char node_p='C';//共同祖先,需要定位的节点1(字母)
char node_q='E';//共同祖先,需要定位的节点2(字母)
///--------以 上 内 容 可 以 修 改 ----------------
printf("---开始测试---\n");
printf("icoding\n路径&&共同祖先\n");
printf(">>正在根据定位串生成树,若生成异常请检查定位码是否正确\n");
//检查nodes是否合法(所有元素是否均为大写字母或者.)
int check[27]={0};
for(int i=0;i<strlen(nodes);i++){
if(nodes[i]=='.'||nodes[i]>='A' || nodes[i]<='Z'){
if(nodes[i]>='A' && nodes[i]<='Z'){
check[nodes[i]-'A']++;
}
}else{
printf(">>定位串中存在非法字符(不是大写字母或.),请检查定位串是否正确,程序自动终止\n");
return 0;
}
}
for(int i=0;i<26;i++){
if(check[i]!=1||check[i]!=0){
printf(">>定位串中存在重复大写字母,程序自动终止\n");
return 0;
}
}
//检查节点是否在A-Z范围内
if(search_node<'A' || search_node>'Z'){
printf(">>待搜索的节点不在A-Z范围内,请检查输入\n程序自动终止,请修改search_node\n");
return 0;
}
int i=0;//定位串起始点,请勿更改!
BiTree T = _CreateByStr(nodes, &i);
printf(">>树生成完毕\n");
printf("##打印树的图形较大时,为了展示效果,请关闭树的打印功能,开启打印树的先序遍历串或换用图形小的树。\n 若需要请修改main函数的print\n\n--------\n");
if(print==1||print==3){
printf(">>打印树,树的打印代码来自于CSDN博主@冀中阿板,若侵权请联系删除,要查找的节点已用*标注\n");
printBiTree(T,search_node);
putchar('\n');
}
if(print==2||print==3){
printf(">>打印树的先序遍历串,要查找的节点已用[]标注\n\n");
printPreOrder(T,search_node);
putchar('\n');
}
Stack s;
init_stack(&s);
BiTNode* node = Search(T, search_node);
printf("\n--------\n>>正在查找节点:%c\n", search_node);
bool ret;
ret=path(T, node, &s);
printf(">>查找完毕");
if(ret){
printf("函数返回true\t正在打印路径\n");
//倒序打印路径
int cou_k=0;
while(!is_empty(&s)){
BiTNode* p;
top(&s, &p);
if(cou_k==0){
printf(" %c ", p->data);
cou_k++;
}
else{
printf("--> %c ", p->data);
}
pop(&s, &p);
}
printf("\n\n路径为从节点到根的顺序,因为栈是先进后出,这是正常的\n");
}
else{
printf("函数返回false\t没有找到节点\n");
if(node!=NULL){
printf("\n但是树中确实有%c节点存在,请检查编写的代码!\n", search_node);
if(flag){
printf("因为您的path函数错误,因而我们无法保障共同祖先函数的正常运行,请修改path函数!共同祖先函数将不会运行\n");
flag=false;
}
}
}
if(flag){
printf("-----\n");
printf("根据设置,将继续运行共同祖先测试,请保证先完成path的编写,保证至少90的得分\n");
//检查节点是否在A-Z范围内
if(node_p<'A' || node_p>'Z'){
printf(">>node_p节点不在A-Z范围内,请检查输入\n程序自动终止,请修改search_node\n");
return 0;
}
if(node_q<'A' || node_q>'Z'){
printf(">>node_q节点不在A-Z范围内,请检查输入\n程序自动终止,请修改search_node\n");
return 0;
}
BiTNode* nodep = Search(T, node_p);
BiTNode* nodeq = Search(T, node_q);
if(nodep==NULL||nodeq==NULL){
printf("请留意,无法在图中找到node_p/node_q节点,寻找到的共同祖先应该为空\n");
}
printf("\n>>正在寻找 %c 和 %c 的共同祖先\n", node_p, node_q);
BiTNode* ptr=nearest_ancestor(T, nodep, nodeq);
if(ptr!=NULL){
printf(">>函数有返回值\t共同祖先为:%c\n", ptr->data);
}
else{
printf(">>函数返回指针为空\t未找到共同祖先,可能是您输入的节点不存在或者代码编写错误。\n");
}
}
else{
printf("\n>>您未运行共同祖先的函数,若需要请修改main函数的flag\n");
}
printf("本程序仅供输出结果,不判断结果的正确性\n");
printf("\n---测试结束---\n");
return 0;
}
若不对main函数的内容进行改动,那么输出的结果将是