初冀 2023-04-26 16:33 采纳率: 61%
浏览 10

从数据文件创建二叉树为什么只能读到一行数据


#include <iostream>
using namespace std;
#define max 100
typedef char elementType;
//双亲表示法
typedef struct pNode {
    elementType data;
    int parent;//父节点指针下标
}pTNode;
//双亲表示的树(森林)
typedef struct pTree {
    pTNode node[max];//结点数组
    int n;//结点总数
}pTree;
//初始化树
void initial(pTree& T) {
    T.n = 0;
}
//孩子兄弟链表表示法
typedef struct csNode {
    elementType data;
    struct csNode* firstChild, * nextSibling;
}csNode,*csTree;

//搜索下标为v的结点的第一个孩子节点下标
int firstChild(pTree& T, int v) {
    int w;
    if (v == -1) {
        return -1;
    }
    for (w = 0; w < T.n; w++) {
        if (T.node[w].parent == v) {
            return w;
        }
    }
    return -1;
}
//搜索下标为v结点的下一兄弟结点
int next(pTree& T, int v) {
    int w;
    for (w = v + 1; w < T.n; w++) {
        if (T.node[w].data == T.node[v].data)
            return w;
    }
    return -1;
}
//递归创建一棵孩子兄弟链表表示的树
void create(csNode*& T, pTree& T1, int v) {//以v为根节点
    int w;
    T = new csNode;
    T->data = T1.node[v].data;
    T->firstChild = NULL;
    T->nextSibling = NULL;
    w = firstChild(T1, v);//搜索v第一个孩子结点
    if (w != -1) {
        create(T->firstChild, T1, w);
    }
    w = next(T1, v);//搜索v的下一兄弟结点
    if (w != -1) {
        create(T->nextSibling, T1, w);
    }
}
//从双亲表示的树(森林)创建孩子兄弟链表表示的树(森林)
void createcsTree(csNode*& T, pTree T1) {
    int i;
    //搜索T1的第一个根结点
    for (i = 0; i < T1.n; i++)
    {
        if (T1.node[i].parent == -1)
            break;
    }
    if (i < T1.n)
        create(T, T1, i);
}
void inOrder(csNode* T, int level) {//按先序次序输出森林中每个结点的值及其对应的层次数。
    if (T) {
        cout << "(" << T->data << "," << level << ") "<<endl;   //访问根结点
        inOrder(T->firstChild, level + 1);//T的孩子结点为T的层次加1
        inOrder(T->nextSibling, level);//T的兄弟结点与T的层次相同
    }
}
//删除字符串、字符数组左边空格
void strLTrim(char* str)
{
    int i, j;
    int n = 0;
    n = strlen(str) + 1;
    for (i = 0; i < n; i++)
    {
        if (str[i] != ' ')  //找到左起第一个非空格位置
            break;
    }
    //以第一个非空格字符为首字符移动字符串
    for (j = 0; j < n; j++)
    {
        str[j] = str[i];
        i++;
    }
}
//从文件创建树
int CreateTreeFromFile(char fileName[], pTree& T)
{
    FILE* pFile;                     //定义顺序表的文件指针
    char str[1000];                  //存放读出一行文本的字符串
    char strTemp[10];                //判断是否注释行
    int i = 0, j = 0;
    errno_t err = fopen_s(&pFile,fileName, "r");
    if (!pFile)
    {
        cout<<"错误:文件打开失败."<<endl ;
        return false;
    }
    while (fgets(str, 1000, pFile) != NULL)  //跳过空行和注释行
    {
        strLTrim(str);                  //删除字符串左边空格
        if (str[0] == '\n')               //空行,继续读取下一行
            continue;

        strncpy_s(strTemp, str, 2);         //将str中的前两个字符拷贝到strTemp中
        if (strstr(strTemp, "//") != NULL)  //跳过注释行
            continue;
        else                            //非注释行、非空行,跳出循环
            break;
    }
    //循环结束,str中应该已经是文件标识,判断文件格式
    if (strstr(str, "Binary") == NULL)    {
        cout<<"错误:打开的文件格式错误!\\n"<<endl;
        fclose(pFile);                  //关闭文件
        return false;
    }
    //读取结点数据,到str。跳过空行
    while (fgets(str, 1000, pFile) != NULL)
    {
        strLTrim(str);                  //删除字符串左边空格
        if (str[0] == '\n')               //空行,继续读取下一行
            continue;

        strncpy_s(strTemp, str, 2);
        if (strstr(strTemp, "//") != NULL)  //注释行,跳过,继续读取下一行
            continue;
        else                            //非空行,也非注释行,即图的顶点元素行
            break;
    }
    //结点数据存入树的结点数组
    char* ptr = NULL;
    char* token = strtok_s(str, " ",&ptr);
    int nNum = 0;
    while (token != NULL)
    {
        T.node[nNum].data = *token;
        T.node[nNum].parent = -1;       //父结点指针初始化为-1

        token = strtok_s(NULL, " ",&ptr);

        nNum++;
    }
    //循环读取边(父子队)数据
    int nP;  //父结点数组下标
    int nC;  //子结点数组下标
    elementType Nf, Ns; //父子结点对的两个结点
    while (fgets(str, 1000, pFile) != NULL)    {
        //删除字符串左边空格
        strLTrim(str);
        if (str[0] == '\n')  //空行,继续读取下一行
            continue;
        strncpy_s(strTemp, str, 2);
        if (strstr(strTemp, "//") != NULL)  //注释行,跳过,继续读取下一行
            continue;
        char* token = strtok_s(str, " ",&ptr);  //以空格为分隔符,分割一行数据,写入邻接矩阵
        if (token == NULL)  //分割为空串,失败退出
        {
            cout << "错误:读取树的边数据失败!" << endl;
            fclose(pFile); //关闭文件
            return false;
        }
        Nf = *token;  //获取父结点
        token = strtok_s(NULL, " ",&ptr);  //读取下一个子串,即子结点
        if (token == NULL)  //分割为空串,失败退出
        {
            cout<<"错误:读取树的边数据失败!"<<endl;
            fclose(pFile); //关闭文件
            return false;
        }
        Ns = *token;  //获取边的第二个结点(子结点)
            //取得父结点下标
        for (nP = 0; nP < nNum; nP++)
        {
            if (T.node[nP].data == Nf)  //从顶点列表找到第一个顶点的编号
                break;
        }
        //获取子结点的数组下标
        for (nC = 0; nC < nNum; nC++)
        {
            if (T.node[nC].data == Ns)  //从顶点列表找到第二个顶点的编号
                break;
        }
        T.node[nC].parent = nP;        //nC的父结点的下标为nP
    }
    T.n = nNum;  //树的结点数,即顶点数组的实际大小
    fclose(pFile); //关闭文件
    return true;
}
 int main() {
    pTree T1;
    csNode* T;
    char fileName[100];
    int level = 1;
    cout << "输入打开的文件名:";
    cin >> fileName;
     if (CreateTreeFromFile(fileName, T1)) {
        cout << "数据处理完毕" << endl;
    }
    createcsTree(T, T1);     
    inOrder(T, level);
}
//二叉树数据文件
//二叉树标识--BinaryTree,无此标识将判定文件格式不对。
//每行表示二叉树中的一个结点。由3项组成:
     //第一项是结点元素值;
     //第二项表示此结点有无左子树,其中:1--有左子树,0--无左子树;
     //第三项表示此结点有无右子树,其中:1--有右子树,0--无右子树。
//结点次序(从上到下)必须严格按照先序遍历次序排列。
//文件扩展名没有限制,程序只根据标识“BinaryTree”判定是否二叉树数据文件。
//文件中可以有空行。
//文件可以有注释行,注释行必须以“//”开始,且注释行必须是单独的行,不能混杂在标识行、数据行中
//此二叉树有10个结点

BinaryTree
A  1  1
B  1  1
C  0  0
D  1  0
E  0  0
F  1  1
G  0  1
H  0  0
I  1  0
J  0  0


void outPreOrder(csNode *T,int level)
{
    if(T)
    {
        cout<<"("<<T->data<<","<<level<<")"<<" ";
        outPreOrder(T->firstChild,level+1);
        outPreOrder(T->nextSibling,level);
    }
}

 
int CreateTreeFromFile(char fileName[], pTree &T)
{
    FILE* pFile;                     //定义顺序表的文件指针
    char str[1000];                  //存放读出一行文本的字符串
    char strTemp[10];                //判断是否注释行
 
    int i=0,j=0;
 
 
    pFile=fopen(fileName,"r");
    if(!pFile)
    {
        printf("错误:文件%s打开失败。\n",fileName);
        return false;
    }
 
    while(fgets(str,1000,pFile)!=NULL)  //跳过空行和注释行
    {
 
        strLTrim(str);                  //删除字符串左边空格
        if (str[0]=='\n')               //空行,继续读取下一行
            continue;
 
        strncpy(strTemp,str,2);         //将str中的前两个字符拷贝到strTemp中
        if(strstr(strTemp,"//")!=NULL)  //跳过注释行
            continue;
        else                            //非注释行、非空行,跳出循环
            break;
    }
 
    //循环结束,str中应该已经是文件标识,判断文件格式
    if(strstr(str,"Tree or Forest")==NULL)
    {
        printf("错误:打开的文件格式错误!\n");
        fclose(pFile);                  //关闭文件
        return false;
    }
 
 
    //读取结点数据,到str。跳过空行
    while(fgets(str,1000,pFile)!=NULL)
    {
        strLTrim(str);                  //删除字符串左边空格
        if (str[0]=='\n')               //空行,继续读取下一行
            continue;
 
        strncpy(strTemp,str,2);
        if(strstr(strTemp,"//")!=NULL)  //注释行,跳过,继续读取下一行
            continue;
        else                            //非空行,也非注释行,即图的顶点元素行
            break;
    }
 
    //结点数据存入树的结点数组
    char* token=strtok(str," ");
    int nNum=0;
    while(token!=NULL)
    {
        T.node[nNum].data=*token;
        T.node[nNum].parent=-1;       //父结点指针初始化为-1
 
        token = strtok( NULL, " ");
 
        nNum++;
    }
 
    //循环读取边(父子队)数据
    int nP;  //父结点数组下标
    int nC;  //子结点数组下标
 
    elementType Nf,Ns; //父子结点对的两个结点
    while(fgets(str,1000,pFile)!=NULL)
    {
        //删除字符串左边空格
        strLTrim(str);
        if (str[0]=='\n')  //空行,继续读取下一行
            continue;
 
        strncpy(strTemp,str,2);
        if(strstr(strTemp,"//")!=NULL)  //注释行,跳过,继续读取下一行
            continue;
 
        char* token=strtok(str," ");  //以空格为分隔符,分割一行数据,写入邻接矩阵
 
        if(token==NULL)  //分割为空串,失败退出
        {
            printf("错误:读取树的边数据失败!\n");
            fclose(pFile); //关闭文件
            return false;
        }
        Nf=*token;  //获取父结点
 
        token = strtok( NULL, " ");  //读取下一个子串,即子结点
        if(token==NULL)  //分割为空串,失败退出
        {
            printf("错误:读取树的边数据失败!\n");
            fclose(pFile); //关闭文件
            return false;
        }
 
        Ns=*token;  //获取边的第二个结点(子结点)
            //取得父结点下标
        for(nP=0;nP<nNum;nP++)
        {
            if(T.node[nP].data==Nf)  //从顶点列表找到第一个顶点的编号
                break;
        }
           //获取子结点的数组下标
        for(nC=0;nC<nNum;nC++)
        {
            if(T.node[nC].data==Ns)  //从顶点列表找到第二个顶点的编号
                break;
        }
 
        T.node[nC].parent=nP;        //nC的父结点的下标为nP
    }
 
    T.n=nNum;  //树的结点数,即顶点数组的实际大小
 
    fclose(pFile); //关闭文件
    return true;
}
 
//搜索双亲表示中,下标w的下一个兄弟结点,返回兄弟结点的下标
int next(pTree T,int w)
{
    int i;
    for(i=w+1;i<T.n;i++)
    {
        if(T.node[w].parent==T.node[i].parent)
            return i;
    }
    return -1;
}
 
//递归创建一棵孩子兄弟链表表示的树
void create(csNode *&T,pTree &T1,int v)
{
    int w;
    T=new csNode;
    T->data=T1.node[v].data;
    T->firstChild=NULL;
    T->nextSibling=NULL;
    w=firstChild(T1,v);  //搜索v的第一个孩子结点
    if(w!=-1)
    {
        create(T->firstChild,T1,w);
    }
 
    w=next(T1,v);       //搜索v的下一个兄弟结点
    if(w!=-1)
    {
        create(T->nextSibling,T1,w);
    }
}
 
//从双亲表示的树(森林)创建孩子兄弟链表表示的树(森林)
void createCsTree(csNode *&T,pTree T1)
{
    int i;
    //搜索T1的第一个根结点
    for(i=0;i<T1.n;i++)
    {
        if(T1.node[i].parent==-1)   //找到第一个根结点
            break;
    }
    if(i<T1.n)
        create(T,T1,i);
}

 

img


图1是我写的代码,图二是文件截图,图三是借鉴的别人的代码,我感觉我是原模原样的超抄的请问哪里有错误啊,为什么只能输出一行就不行了

  • 写回答

1条回答 默认 最新

报告相同问题?

问题事件

  • 创建了问题 4月26日

悬赏问题

  • ¥50 AI大模型精调(百度千帆、飞浆)
  • ¥15 关于#c语言#的问题:我在vscode和codeblocks中编写c语言时出现打不开源文件该怎么办
  • ¥15 非科班怎么跑代码?如何导数据和调参
  • ¥15 福州市的全人群死因监测点死亡原因报表
  • ¥15 Altair EDEM中生成一个颗粒,并且各个方向没有初始速度
  • ¥15 系统2008r2 装机配置推荐一下
  • ¥500 服务器搭建cisco AnyConnect vpn
  • ¥15 悬赏Python-playwright部署在centos7上
  • ¥15 psoc creator软件有没有人能远程安装啊
  • ¥15 快速扫描算法求解Eikonal方程咨询