#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);
}
图1是我写的代码,图二是文件截图,图三是借鉴的别人的代码,我感觉我是原模原样的超抄的请问哪里有错误啊,为什么只能输出一行就不行了