就算世界荒芜,总有一个人,他会是你的信徒。 ----《独木舟里的星星》
第一步:创建一个节点
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日