C++ 从.txt文件初始化列表中的节点

C++ 从.txt文件初始化列表中的节点,c++,io,linked-list,C++,Io,Linked List,目前有一个自定义的链表类,可以很好地工作 我实现了一个函数,可以在程序退出时将每个节点的所有内容导出到一个.txt文件中。现在我想在程序开始时导入相同的文件以重新填充列表,这就是我遇到一些困难的地方。(关于>和的建议: 保留指向最后一个节点的指针。 这将加快附件的速度,使生活更轻松 创建append方法。 这将在列表末尾追加一个节点。对于一般插入也很有用 导入方法使用append方法。 import方法创建一个新节点,用文件中的数据初始化它,然后调用append方法 为节点类实现操作符>>(is

目前有一个自定义的链表类,可以很好地工作

我实现了一个函数,可以在程序退出时将每个节点的所有内容导出到一个.txt文件中。现在我想在程序开始时导入相同的文件以重新填充列表,这就是我遇到一些困难的地方。(关于
>
的建议:

保留指向最后一个节点的指针。 这将加快附件的速度,使生活更轻松

创建append方法。 这将在列表末尾追加一个节点。对于一般插入也很有用

导入方法使用append方法。 import方法创建一个新节点,用文件中的数据初始化它,然后调用append方法

节点
类实现
操作符>>(istream&)
。 将I/O封装到一个中心位置。将有关类内部对象的知识留给类,而不是
列表

节点

替换为get/set方法和link_to()方法。这将松开
节点
列表
之间的耦合非常简单,您可以像我下面描述的那样读取该文件

void List::importData(const char *filePath)
{
    // open the file.
    std::ifstream file(filePath);

    // storage for the values read from the stream.
    std::string symbol;
    int shares;

    // here we read the symbol from the file stream, with "file >> symbol".  the
    // return value of that expression is the stream 'file', so we can chain 
    // that to reading the share count with "file >> symbol >> shares".  notice
    // that we use this in a conditional - this is because the stream will 
    // evaluate to 'true' if there is more data to read, or 'false' otherwise.
    while ((file >> symbol >> shares))
    {
        // create the new node
        addToBack(symbol, shares);
    }
}
列表
/
节点
安排的一些潜在改进。下面我给出的内容忽略了复制分配复制构造的问题。目前来看,如果你做这两件事中的任何一件,它都会爆炸-这只是一个需要解决的练习。但最终,我建议使用e> std::list
,其中
StockItem
仅包含
符号
share\u count

#include <fstream>
#include <memory>

// the node class used in the list.  note that I have not declared the list
// to be a friend of the node.  its needed as the data members are public.  if
// you dont want the data to be public (e.g. you want to enforce certain
// operations) make them private, and provide accessor functions.  in this case
// StockNode is a struct, making the data members public by default.
struct StockNode
{
    std::string mSymbol;
    int mShares;
    StockNode *mNext;

    // custom constructor, which populates the symbol and shares.
    StockNode(const std::string& symbol, int shares)
    : mSymbol(symbol), mShares(shares), mNext(0)
    {
    }
};

class StockList
{
    // we store the head AND the tail of the list.  storing the tail allows for
    // fast appends.
    StockNode *mHead;
    StockNode *mTail;

  public:
    // we override the default constructor to initialize the head/tail pointers
    // to 0 (null).
    StockList() : mHead(0), mTail(0)
    {
    }

    // destructor - since we are using raw pointers, we need to manage the 
    // freeing of the StockNodes ourselfs (again, if we used a 
    // std::list<StockNode> we could have avoided this.
    ~StockList()
    {
        clear();
    }

    void clear()
    {
        StockNode *node = mHead;

        // while we havent reached the end of the list.
        while (node)
        {
            // find the next element
            StockNode *temp = node->mNext;

            // free the memory for the current element.
            delete node;

            // set node to the next element in the list.
            node = temp;
        }

        // reset the pointers
        mHead = 0;
        mTail = 0;
    }

    // appends a node to the list.  i have called it push_back in line with the
    // standard library implementation std::list (which you would normally use
    // here, but it looks like this is homework).  notice that the parameter
    // is not a pointer, but a std::auto_ptr.  look up the documentation for it
    // to see exactly how it works.  its not *required* here, but i use it so 
    // the interface documents that we are taking ownership of the node.
    void push_back(std::auto_ptr<StockNode> stockNode)
    {
        // notice below the calls to "release", this stops the std::auto_ptr
        // managing the memory - so it doesn't free the memory when we still 
        // need it.

        if (mTail)
        {
            // the tail is set, write the new value.
            mTail->mNext = stockNode.release();
            mTail = mTail->mNext;
        }
        else
        {
            // no tail set means this is the first element, set the head and
            // the tail.
            mHead = stockNode.release();
            mTail = mHead;
        }
    }

    // ... implement other methods for looking up StockNodes, etc...

    void exportData(const std::string& filePath) const
    {
        std::ofstream file(filePath.c_str());

        for (StockNode *node = mHead; node; node = node->mNext)
        {
            // note that i have used '\n' instead of std::endl.  this is 
            // because std::endl prints the '\n' and flushes the stream
            // as we are writing to file, i figure it'll be a little quicker
            // if it doesnt flush to disk after every line.
            file << node->mSymbol << " " << node->mNext << '\n';
        }
    }

    void importData(const std::string& filePath)
    {
        std::ifstream file(filePath.c_str());

        std::string symbol;
        int shares;

        while ((file >> symbol >> shares))
        {
            push_back(std::auto_ptr<StockNode>(new StockNode(symbol, shares)));
        }
    }
};
#包括
#包括
//列表中使用的节点类。请注意,我尚未声明列表
//成为节点的朋友。因为数据成员是公共的,所以需要它。如果
//您不希望数据公开(例如,您希望强制执行某些
//操作)使它们私有,并提供访问器函数
//StockNode是一个结构,默认情况下使数据成员公开。
结构StockNode
{
std::字符串mSymbol;
国际共享;
StockNode*mNext;
//自定义构造函数,用于填充符号和共享。
StockNode(常量std::字符串和符号,整数共享)
:mSymbol(符号)、mShares(股份)、mNext(0)
{
}
};
班级存货清单
{
//我们存储列表的头和尾。存储尾允许
//快速附加。
StockNode*mHead;
StockNode*mTail;
公众:
//我们重写默认构造函数来初始化头/尾指针
//设置为0(null)。
StockList():mHead(0),mTail(0)
{
}
//析构函数-因为我们使用的是原始指针,所以需要管理
//释放我们自己(同样,如果我们使用
//我们本可以避免这种情况。
~StockList()
{
清除();
}
无效清除()
{
StockNode*node=mHead;
//虽然我们还没有到达列表的末尾。
while(节点)
{
//找到下一个元素
StockNode*temp=node->mNext;
//释放当前元素的内存。
删除节点;
//将节点设置为列表中的下一个元素。
节点=温度;
}
//重置指针
mHead=0;
mTail=0;
}
//将一个节点追加到列表中。根据
//标准库实现std::list(通常使用
//这里,但看起来这是家庭作业)。请注意
//不是指针,而是std::auto_ptr。请在文档中查找它
//看看它到底是怎么工作的。这里不需要,但我就是这么用的
//接口文档表明我们正在获取节点的所有权。
无效回推(标准::自动回推stockNode)
{
//请注意,在调用“release”的下面,这将停止std::auto_ptr
//管理内存—这样当我们仍然
//我需要它。
如果(mTail)
{
//设置尾部后,写入新值。
mTail->mNext=stockNode.release();
mTail=mTail->mNext;
}
其他的
{
//无尾集意味着这是第一个元素,设置头和尾
//尾巴。
mHead=stockNode.release();
mTail=mHead;
}
}
//…实现查找StockNodes等的其他方法。。。
void exportData(const std::string和filePath)const
{
std::of流文件(filePath.c_str());
对于(StockNode*node=mHead;node;node=node->mNext)
{
//请注意,我使用了“\n”而不是std::endl。这是
//因为std::endl打印'\n'并刷新流
//因为我们正在写文件,我想会快一点
//如果它没有在每行之后刷新到磁盘。
文件mSymbol symbol>>共享)
{
推回(std::auto_ptr(新股票节点(符号,股票));
}
}
};

是的,如果您的列表有一个界面可以向其中添加新节点,可能会有所帮助!您的
导入数据如何可能工作,您必须事先知道列表中可能存在的所有节点!?!最好有一个
向后推
和一个新节点…因此步骤是构造新节点,从流读取,向后推。查看这将如何处理
std::list
。显然,我也必须消除While语句,因为列表一开始总是空的。
class Node
{
private:
    friend class List;
    string symbol;
    int shares;
    Node *next;
public:
    Node() 
        : next(0)
    {
    }
void List::importData(const char *filePath)
{
    // open the file.
    std::ifstream file(filePath);

    // storage for the values read from the stream.
    std::string symbol;
    int shares;

    // here we read the symbol from the file stream, with "file >> symbol".  the
    // return value of that expression is the stream 'file', so we can chain 
    // that to reading the share count with "file >> symbol >> shares".  notice
    // that we use this in a conditional - this is because the stream will 
    // evaluate to 'true' if there is more data to read, or 'false' otherwise.
    while ((file >> symbol >> shares))
    {
        // create the new node
        addToBack(symbol, shares);
    }
}
#include <fstream>
#include <memory>

// the node class used in the list.  note that I have not declared the list
// to be a friend of the node.  its needed as the data members are public.  if
// you dont want the data to be public (e.g. you want to enforce certain
// operations) make them private, and provide accessor functions.  in this case
// StockNode is a struct, making the data members public by default.
struct StockNode
{
    std::string mSymbol;
    int mShares;
    StockNode *mNext;

    // custom constructor, which populates the symbol and shares.
    StockNode(const std::string& symbol, int shares)
    : mSymbol(symbol), mShares(shares), mNext(0)
    {
    }
};

class StockList
{
    // we store the head AND the tail of the list.  storing the tail allows for
    // fast appends.
    StockNode *mHead;
    StockNode *mTail;

  public:
    // we override the default constructor to initialize the head/tail pointers
    // to 0 (null).
    StockList() : mHead(0), mTail(0)
    {
    }

    // destructor - since we are using raw pointers, we need to manage the 
    // freeing of the StockNodes ourselfs (again, if we used a 
    // std::list<StockNode> we could have avoided this.
    ~StockList()
    {
        clear();
    }

    void clear()
    {
        StockNode *node = mHead;

        // while we havent reached the end of the list.
        while (node)
        {
            // find the next element
            StockNode *temp = node->mNext;

            // free the memory for the current element.
            delete node;

            // set node to the next element in the list.
            node = temp;
        }

        // reset the pointers
        mHead = 0;
        mTail = 0;
    }

    // appends a node to the list.  i have called it push_back in line with the
    // standard library implementation std::list (which you would normally use
    // here, but it looks like this is homework).  notice that the parameter
    // is not a pointer, but a std::auto_ptr.  look up the documentation for it
    // to see exactly how it works.  its not *required* here, but i use it so 
    // the interface documents that we are taking ownership of the node.
    void push_back(std::auto_ptr<StockNode> stockNode)
    {
        // notice below the calls to "release", this stops the std::auto_ptr
        // managing the memory - so it doesn't free the memory when we still 
        // need it.

        if (mTail)
        {
            // the tail is set, write the new value.
            mTail->mNext = stockNode.release();
            mTail = mTail->mNext;
        }
        else
        {
            // no tail set means this is the first element, set the head and
            // the tail.
            mHead = stockNode.release();
            mTail = mHead;
        }
    }

    // ... implement other methods for looking up StockNodes, etc...

    void exportData(const std::string& filePath) const
    {
        std::ofstream file(filePath.c_str());

        for (StockNode *node = mHead; node; node = node->mNext)
        {
            // note that i have used '\n' instead of std::endl.  this is 
            // because std::endl prints the '\n' and flushes the stream
            // as we are writing to file, i figure it'll be a little quicker
            // if it doesnt flush to disk after every line.
            file << node->mSymbol << " " << node->mNext << '\n';
        }
    }

    void importData(const std::string& filePath)
    {
        std::ifstream file(filePath.c_str());

        std::string symbol;
        int shares;

        while ((file >> symbol >> shares))
        {
            push_back(std::auto_ptr<StockNode>(new StockNode(symbol, shares)));
        }
    }
};