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

Initializing nodes in a list from a .txt file

本文关键字:节点 列表 初始化 txt 文件      更新时间:2023-10-16

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

我实现了一个函数,该函数可以在程序退出时将每个Node的所有内容导出为.txt文件。现在我想导入相同的文件,以便在程序开始时重新填充列表,这就是我遇到一些困难的地方。(>><<操作符是重载的)并且这个整个链表类是特定于这个程序的,并不是真正意义上的可重用性。

my export function:

void List::exportData(){
    Node *currentPtr = Head;
    cout<<"Saving Data..."<<endl;
    ofstream fileOut("stock_transaction_history.txt");
    while (currentPtr != 0){
        fileOut<< currentPtr->symbol << " " <<currentPtr->shares<<endl;
        currentPtr = currentPtr->next; //iterates down the list
    }
}

现在我完全被导入数据特性困住了。如果需要的话,我还有一个函数addToBack((Node *newPtr)供我使用。

void List::importData(){
    Node *currentPtr
    ifstream stockIn("stock_transaction_history.txt"); 
    }
    stockIn >> currentPtr->symbol >>currentPtr ->shares;//(Node(tempSymbol, num));
    currentPtr = currentPtr->next;
    stockIn.close();

}

我想我可能不得不通过Node *tempPtr=new Node();的一些东西来调用addToBack,或者只是调用我节点的通用data部分?

这是我的node.h

class Node
{
private:
    friend class List;
    string symbol;
    int shares;
    Node *next;
public:
    Node() 
        : next(0)
    {
    }

建议:

保持指向最后一个节点的指针

这将加快追加,使工作更容易。

创建附加方法。

这将在列表的末尾添加一个节点。对于一般插入也很有用。

导入方法使用附加方法。

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

Node类实现operator >>(istream&)

将I/O封装到一个中心位置。把关于类内部关系的知识留给类,而不是留给List

Node中删除friend声明

替换为get/set方法和link_to()方法。这将放松NodeList之间的耦合

非常简单,您可以按照我下面描述的方式读取该文件。

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);
    }
}

List/Node安排的一些潜在改进。我下面给出的忽略了复制赋值复制构造的问题。事实上,如果你做了这两件事中的任何一件,它都会爆炸——这是一个需要解决的问题。但最终,我建议使用std::list<StockItem>,其中StockItem只包含symbolshare_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)));
        }
    }
};