就算世界荒芜,总有一个人,他会是你的信徒。 ----《独木舟里的星星》
第一步:创建一个节点
template
<
typename
T
>
class
Node
{
public:
Node
(T data)
{
m_data
=
data;
m_pNext
=
NULL
;
}
const
T
&
getData
()
{
return
m_data;
}
Node
<
T
>
*
&
getNext
()
{
return
m_pNext;
}
private:
T m_data;
Node
*
m_pNext;
};
这里用到了类模板,因为这里的数据部分类型无法确定。
第二步:创建链表
template
<
typename
T
>
class
List
{
public:
List
()
{
m_iLen
=
0
;
m_pFirstNode
=
NULL
;
}
Node
<
T
>*
getFirstNode
()
{
return
m_pFirstNode;
}
int
getListLen
()
{
return
m_iLen;
}
void
insert
(T data)
{
Node
<
T
>
*
node
=
new
Node
<
T
>
(data);
node->
getNext
()
=
m_pFirstNode;
m_pFirstNode
=
node;
m_iLen
++
;
}
void
display
()
{
Node
<
T
>
*
tmp
=
m_pFirstNode;
for
(
int
i
=
0
; i
<
m_iLen; i
++
)
{
cout
<<
tmp->
getData
()
<<
endl;
tmp
=
tmp->
getNext
();
}
}
private:
int
m_iLen;
Node
<
T
>
*
m_pFirstNode;
};
一般习惯将链表头定义的与其他节点不同,链表头可以放很多信息,例如:链表长度、作者、修改人、创建日期等等,当后面节点加入的时候不会每个节点都有这些信息。
。。。可以在主函数中试一下链表。。。
int main(void)
{
List<int> intList;
intList.insert(2);
intList.insert(1);
intList.insert(5);
intList.insert(3);
intList.insert(4);
cout << "打印链表" << endl;
intList.display();
第四步:
链表写好后,我们将链表写入文件中
fstream file1;
file1.open("int.txt");
file1 << intList;
将文件以读写的方式打开,记得要提前创建文件int.txt,因为以读写方式打开文件的时候,如果文件不存在,程序不会自动创建。同样,以只读打开也是一样,只有以只写打开的时候才会自动创建。如果仅仅这样写,编译的时候肯定
无法通过
,因为无法将一个链表类型的数据直接写入文件。我们需要将
<<运算符重载。
重载运算符: <<
template<typename T>
fstream &operator << (fstream &file, List<T> &list)
{
Node<T> *tmp = list.getFirstNode();
int len = list.getListLen();
for(int i = 0; i < len; i++)
{
file << tmp->getData();
tmp = tmp->getNext();
}
return file;
}
写完后,再执行file1.intList; 就不会报错了。
第五步:从文件中读取数据到链表
file1.seekg(0, ios_base::beg);
cout << "--------读取文件里的链表------------" << endl;
List<int> intList2;
int data = 0;
while(1)
{
file1 >> data;
intList2.insert(data);
if(file1.eof())
{
break;
}
}
intList2.display();
file1.close();
思路很简单,首先将文件的读写位置设置到首部,因为我们在写入文件的时候,读写位置到了最后,这时候直接读是读不到数据的。然后将文件里的内容读到临时变量data中,然后插入的时候调用有参构造函数,输入参数data,生成新链表。读取完退出,最后打印显示。
上面的链表只针对一般的数据类型有效,如果我们的数据部分是自己构造的类呢?
第一步:创建一个类(以student为例)
class
Student
{
public:
Student
(
int
id
=
1000
, string name
=
" "
,
float
score
=
0.0f
)
{
m_iId
=
id;
m_strName
=
name;
m_fScore
=
score;
}
friend
ostream
&
operator
<<
(ostream
&
out,
const
Student
&
stu);
private:
int
m_iId;
string m_strName;
float
m_fScore;
};
第二步:重载运算符 <<
ostream
&
operator
<<
(ostream
&
out,
const
Student
&
stu)
{
out
<<
" "
<<
stu.
m_iId
<<
" "
<<
stu.
m_strName
<<
" "
<<
stu.
m_fScore
;
}
这里重载是因为1、打印的时候无法直接直接输入一个Student类型,即:cout << stu 是无法直接实现的, 2、写入文件的时候同样无法直接写入一个Student类型。但为什么只重载ostream中的<<就可以同时实现两个呢?因为fstream继承了iostream,而iostream又继承了istream和ostream。关系如下图:
这之后的操作大同小异,大家可以自行理解。
下面是全代码,以及打印结果:
#include
<iostream>
#include
<fstream>
using
namespace
std
;
class
Student
{
public:
Student
(
int
id
=
1000
, string name
=
" "
,
float
score
=
0.0f
)
{
m_iId
=
id;
m_strName
=
name;
m_fScore
=
score;
}
friend
ostream
&
operator
<<
(ostream
&
out,
const
Student
&
stu);
//friend fstream &operator << (fstream &file, const Student &stu);
private:
int
m_iId;
string m_strName;
float
m_fScore;
};
ostream
&
operator
<<
(ostream
&
out,
const
Student
&
stu)
{
out
<<
" "
<<
stu.
m_iId
<<
" "
<<
stu.
m_strName
<<
" "
<<
stu.
m_fScore
;
}
template
<
typename
T
>
class
Node
{
public:
Node
(T data)
{
m_data
=
data;
m_pNext
=
NULL
;
}
const
T
&
getData
()
{
return
m_data;
}
Node
<
T
>
*
&
getNext
()
{
return
m_pNext;
}
private:
T m_data;
Node
*
m_pNext;
};
template
<
typename
T
>
class
List
{
public:
List
()
{
m_iLen
=
0
;
m_pFirstNode
=
NULL
;
}
Node
<
T
>*
getFirstNode
()
{
return
m_pFirstNode;
}
int
getListLen
()
{
return
m_iLen;
}
void
insert
(T data)
{
Node
<
T
>
*
node
=
new
Node
<
T
>
(data);
node->
getNext
()
=
m_pFirstNode;
m_pFirstNode
=
node;
m_iLen
++
;
}
void
display
()
{
Node
<
T
>
*
tmp
=
m_pFirstNode;
for
(
int
i
=
0
; i
<
m_iLen; i
++
)
{
cout
<<
tmp->
getData
()
<<
endl;
tmp
=
tmp->
getNext
();
}
}
private:
int
m_iLen;
Node
<
T
>
*
m_pFirstNode;
};
template
<
typename
T
>
fstream
&
operator
<<
(fstream
&
file, List
<
T
>
&
list)
{
Node
<
T
>
*
tmp
=
list.
getFirstNode
();
int
len
=
list.
getListLen
();
for
(
int
i
=
0
; i
<
len; i
++
)
{
file
<<
tmp->
getData
();
tmp
=
tmp->
getNext
();
}
return
file;
}
int
main
(
void
)
{
List
<
int
>
intList;
intList.
insert
(
2
);
intList.
insert
(
1
);
intList.
insert
(
5
);
intList.
insert
(
3
);
intList.
insert
(
4
);
cout
<<
"打印链表"
<<
endl;
intList.
display
();
fstream file1;
file1.
open
(
"int.txt"
);
file1
<<
intList;
file1.
seekg
(
0
, ios_base::beg);
cout
<<
"--------读取文件里的链表------------"
<<
endl;
List
<
int
>
intList2;
int
data
=
0
;
while
(
1
)
{
file1
>>
data;
intList2.
insert
(data);
if
(file1.
eof
())
{
break
;
}
}
intList2.
display
();
file1.
close
();
cout
<<
endl
<<
endl;
List
<
Student
>
stuList;
stuList.
insert
(
Student
(
1001
,
"aa"
,
23
));
stuList.
insert
(
Student
(
1002
,
"bb"
,
14
));
stuList.
insert
(
Student
(
1003
,
"cc"
,
53
));
stuList.
insert
(
Student
(
1004
,
"dd"
,
25
));
stuList.
insert
(
Student
(
1005
,
"ee"
,
94
));
cout
<<
"打印链表"
<<
endl;
stuList.
display
();
fstream file2;
file2.
open
(
"student.txt"
);
file2
<<
stuList;
file2.
seekg
(
0
, ios_base::beg);
cout
<<
"-------读取文件里的链表------------"
<<
endl;
List
<
Student
>
stuList2;
int
id
=
0
;
string name
=
" "
;
float
score
=
0.0f
;
while
(
1
)
{
name.
clear
();
file2
>>
id
>>
name
>>
score;
stuList2.
insert
(
Student
(id, name, score));
if
(file2.
eof
())
{
break
;
}
}
stuList2.
display
();
file2.
close
();
return
0
;
}
QQ:1786610699 倔强的木木 2017年8月26日