【问题标题】:Sorting Input in Vector of Doubly Linked List Template (C++)双向链表模板向量中的输入排序(C++)
【发布时间】:2014-03-03 02:44:39
【问题描述】:

我正在编写一个程序,该程序从一个 .txt 文件中获取输入,该文件包含一个人的名字、姓氏、9 位通用标识号 (UIN) 和他们的电话号码。我应该将此文件的输入读入双向链接列表的向量,其中向量的元素0对应于带有第一个字母'A'的姓氏的双向链接列表,元素1对应于最后的双向链接列表第一个字母“B”的名字等等。

我的代码可以从文件中读取数据并将其放入正确的列表中,但这些列表未排序。我应该在我的 TemplateDoublyLinkedList 中编写一个插入函数,它将新元素放置在列表中的正确位置,假设列表已排序,并且在我插入新元素后将保持正确排序。

我的错误不知何故来自这个函数,但我得到了非常模糊的链接器错误(这意味着我可能犯了一些愚蠢的错误),我不知道如何修复它。这是我的代码:

TemplateDoublyLinkedList.h

#include "Record.h"
#include <cstdlib>
#include <iostream>
#include <string>
#include <cstdio>
#include <sstream>
#pragma once
using namespace std;
template <typename T>
class DoublyLinkedList; // class declaration

// list node
template <typename T>
class DListNode {
private: T obj;
  DListNode<T> *prev, *next;
  friend class DoublyLinkedList<T>;
public:
  DListNode<T>(T object = T(), DListNode<T> *p = NULL, DListNode<T> *n = NULL)
    : obj(object), prev(p), next(n) {}
  T getElem() const { return obj; }
  DListNode<T> * getNext() const { return next; }
  DListNode<T> * getPrev() const { return prev; }
};

// doubly linked list
template <typename T>
class DoublyLinkedList {
protected: DListNode<T> header, trailer;
public:
  DoublyLinkedList<T>() : header(T()), trailer(T()) // constructor
  { header.next = &trailer; trailer.prev = &header; }
  DoublyLinkedList<T>(const DoublyLinkedList<T>& dll); // copy constructor
  ~DoublyLinkedList<T>(); // destructor
  DoublyLinkedList<T>& operator=(const DoublyLinkedList<T>& dll); // assignment operator
  // return the pointer to the first node
  DListNode<T> *getFirst() const { return header.next; } 
  // return the pointer to the trailer
  const DListNode<T> *getAfterLast() const { return &trailer; }
  // return if the list is empty
  bool isEmpty() const { return header.next == &trailer; }
  T first() const; // return the first object
  T last() const; // return the last object
  void insertFirst(T newobj); // insert to the first of the list
  T removeFirst(); // remove the first node
  void insertLast(T newobj); // insert to the last of the list
  T removeLast(); // remove the last node
  DListNode<T> *insert(T& newobj);
};
// output operator
template <typename T>
ostream& operator<<(ostream& out, const DoublyLinkedList<T>& dll);

// extend range_error from <stdexcept>
struct EmptyDLinkedListException : std::range_error {
  explicit EmptyDLinkedListException(char const* msg=NULL): range_error(msg) {}
};

// copy constructor
template <typename T>
DoublyLinkedList<T>::DoublyLinkedList(const DoublyLinkedList<T>& dll)
{
  header=T();
  trailer=T();
  header.next = &trailer; trailer.prev = &header;
  if (dll.isEmpty()) 
      return;

  DListNode<T>* current = dll.getFirst();
  while (current != dll.getAfterLast()) {
      T newObj = current->obj;
      insertLast(newObj);
      current = current->getNext();
  }

}
// assignment operator
template <typename T>
DoublyLinkedList<T>& DoublyLinkedList<T>::operator=(const DoublyLinkedList<T>& dll)
{
  delete this;

  header.next = &trailer; trailer.prev = &header;

  DListNode<T>* current = dll.getFirst();
  while (current != dll.getAfterLast()) {
      T newObj = current->obj;
      insertLast(newObj);
      current = current->getNext();
  }

  return *this;
}
// insert the object to the first of the linked list
template <typename T>
void DoublyLinkedList<T>::insertFirst(T newobj)
{ 
  DListNode<T> *newNode = new DListNode<T>(newobj, &header, header.next);
  header.next->prev = newNode;
  header.next = newNode;
}
// insert the object to the last of the linked list
template <typename T>
void DoublyLinkedList<T>::insertLast(T newobj)
{
  DListNode<T> *newNode = new DListNode<T>(newobj, trailer.prev,&trailer);
  trailer.prev->next = newNode;
  trailer.prev = newNode;
}
// remove the first object of the list
template <typename T>
T DoublyLinkedList<T>::removeFirst()
{ 
  if (isEmpty())
    throw EmptyDLinkedListException("Empty Doubly Linked List");
  DListNode<T> *node = header.next;
  node->next->prev = &header;
  header.next = node->next;
  T obj = node->obj;
  delete node;
  return obj;
}
// remove the last object of the list
template <typename T>
T DoublyLinkedList<T>::removeLast()
{
  if (isEmpty())
    throw EmptyDLinkedListException("Empty Doubly Linked List");
  DListNode<T> *node = trailer.prev;
  node->prev->next = &trailer;
  trailer.prev = node->prev;
  T obj = node->obj;
  delete node;
  return obj;
}
// destructor
template <typename T>
DoublyLinkedList<T>::~DoublyLinkedList()
{
  DListNode<T> *prev_node, *node = header.next;
  while (node != &trailer) {
    prev_node = node;
    node = node->next;
    delete prev_node;
  }
  header.next = &trailer;
  trailer.prev = &header;
}
// return the first object
template <typename T>
T DoublyLinkedList<T>::first() const
{ 
  if (isEmpty())
    throw EmptyDLinkedListException("Empty Doubly Linked List");
  return header.next->obj;
}
// return the last object
template <typename T>
T DoublyLinkedList<T>::last() const
{
  if (isEmpty())
    throw EmptyDLinkedListException("Empty Doubly Linked List");
  return trailer.prev->obj;
}
// return the list length
template <typename T>
int DoublyLinkedListLength(DoublyLinkedList<T>& dll) {
  DListNode<T> *current = dll.getFirst();
  int count = 0;
  while(current != dll.getAfterLast()) {
    count++;
    current = current->getNext(); //iterate
  }
  return count;
}
// output operator
template <typename T>
ostream& operator<<(ostream& out, const DoublyLinkedList<T>& dll) {
  DListNode<T> *current = dll.getFirst();
  while (current != dll.getAfterLast()) {
      out << current->getElem() << '\n';
      current = current->getNext();
  }
  return out;
}

template <typename T>
DListNode<T> *insert(T& obj) {
    DListNode<T> *current = this->getFirst();
    while (obj < current->obj) {
        current = current->getNext();
    }

    DListNode<T> *newNode = new DListNode<T>(obj, current->prev, current);
    curren->prev = newNode;
    added->prev->next = added;
    return newNode;
}

Record.h(用于我的 ADT 的类,包含每个“人员”及其姓名、UIN 和电话号码)

#include <iostream>
#include <cstdlib>
#include <string>
#pragma once
using namespace std;

class Record {
private:
    string lastName, firstName, universalIdentificationNumber, phoneNumber;
public:
    Record(string last = "EMPTY", string first = "EMPTY", string UIN = "EMPTY", string phone = "EMPTY") : 
        lastName(last), firstName(first), universalIdentificationNumber(UIN), phoneNumber(phone) {}
    bool operator < (const Record& r);

    string getLast() const { return lastName; }
    string getFirst() const { return firstName; }
    string getUIN() const { return universalIdentificationNumber; }
    string getPhone() const { return phoneNumber; }

    void setLast(string s) { lastName = s; }
    void setFirst(string s) { firstName = s; }
    void setUIN(string s) { universalIdentificationNumber = s; }
    void setPhone(string s) { phoneNumber = s; }
};

ostream& operator<<(ostream& out, const Record& r);

记录.cpp

#include "Record.h"
#include "TemplateDoublyLinkedList.h"
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;

bool Record::operator < (const Record& r) {
    if (getLast().compare(r.getLast()) < 0) 
        return true;
    if (getLast().compare(r.getLast()) >0)
        return false;
    if (getLast().compare(r.getLast()) == 0) {
        if (getFirst().compare(r.getFirst()) < 0)
            return true;
        if (getFirst().compare(r.getFirst()) > 0)
            return false;
        if (getFirst().compare(r.getFirst()) == 0) {
            if (getUIN().compare(r.getUIN()) < 0) 
                return true;
            if (getUIN().compare(r.getUIN()) > 0)
                return false;
            if (getUIN().compare(r.getUIN()) == 0) {
                if (getPhone().compare(r.getPhone()) < 0)
                    return true;
                if (getPhone().compare(r.getPhone()) > 0)
                    return false;
                if (getPhone().compare(r.getPhone()) == 0)
                    return true;
            }
        }
    }
    return false;
}

ostream& operator<<(ostream& out, const Record& r) {
    out << "Last Name: " << r.getLast() << '\n'
        << "First Name: " << r.getFirst() << '\n'
        << "UIN: " << r.getUIN() << '\n'
        << "Phone Number: " << r.getPhone() << '\n';

    return out;
}

Main.cpp

#include "Record.h"
#include "TemplateDoublyLinkedList.h"
#include <cstdlib>
#include <string>
#include <iostream>
#include <cstdio>
#include <sstream>
#include <vector>
#include <fstream>
using namespace std;

void display(vector<DoublyLinkedList<Record>>& v) {
    for (int i=0; i<v.size(); ++i) {
        cout << v[i];
    }
}

int firstLetterSort (string s) {
    char firstLetter = s.at(0);
    int location;

    switch (firstLetter) {
    case 'a':
    case 'A':
        location = 0;
        break;
    case 'b':
    case 'B':
        location = 1;
        break;
    case 'c':
    case 'C':
        location = 2;
        break;
    case 'd':
    case 'D':
        location = 3;
        break;
    case 'e':
    case 'E':
        location = 4;
        break;
    case 'f':
    case 'F':
        location = 5;
        break;
    case 'g':
    case 'G':
        location = 6;
        break;
    case 'h':
    case 'H':
        location = 7;
        break;
    case 'i':
    case 'I':
        location = 8;
        break;
    case 'j':
    case 'J':
        location = 9;
        break;
    case 'k':
    case 'K':
        location = 10;
        break;
    case 'l':
    case 'L':
        location = 11;
        break;
    case 'm':
    case 'M':
        location = 12;
        break;
    case 'n':
    case 'N':
        location = 13;
        break;
    case 'o':
    case 'O':
        location = 14;
        break;
    case 'p':
    case 'P':
        location = 15;
        break;
    case 'q':
    case 'Q':
        location = 16;
        break;
    case 'r':
    case 'R':
        location = 17;
        break;
    case 's':
    case 'S':
        location = 18;
        break;
    case 't':
    case 'T':
        location = 19;
        break;
    case 'u':
    case 'U':
        location = 20;
        break;
    case 'v':
    case 'V':
        location = 21;
        break;
    case 'w':
    case 'W':
        location = 22;
        break;
    case 'x':
    case 'X':
        location = 23;
        break;
    case 'y':
    case 'Y':
        location = 24;
        break;
    case 'z':
    case 'Z':
        location = 25;
    }
    return location;
}

int main() {
    vector<DoublyLinkedList<Record>> phoneBook(26);
    const string phoneBookFile = "PhoneBook";
    string searchedLast, searchedFirst, searchedUIN;
    int firstLetter;

    ifstream ist(phoneBookFile.c_str());
    ist.open("PhoneBook.txt");
    if (ist.is_open()) {
        while (!ist.eof()) {
            Record nextRecord;
            string first, last, UIN, phone, empty;

            getline(ist, last);
            getline(ist, first);
            getline(ist, UIN);
            getline(ist, phone);
            getline(ist, empty);

            nextRecord.setLast(last);
            nextRecord.setFirst(first);
            nextRecord.setUIN(UIN);
            nextRecord.setPhone(phone);

            int location = firstLetterSort(last);
            phoneBook[location].insert(nextRecord);
        }
    }

    display(phoneBook);
}

还有我的编译器输出的错误:

1>Main.obj : error LNK2019: unresolved external symbol "public: class DListNode<class Record> * __thiscall DoublyLinkedList<class Record>::insert(class Record &)" (?insert@?$DoublyLinkedList@VRecord@@@@QAEPAV?$DListNode@VRecord@@@@AAVRecord@@@Z) referenced in function _main
1>C:\Users\Snyperanihilatr\Documents\Visual Studio 2012\Projects\Phonebook\Debug\Phonebook.exe : fatal error LNK1120: 1 unresolved externals

【问题讨论】:

  • 我一看到这个就停止阅读:delete this;,然后是一堆被引用的成员变量。编译器错误只是冰山一角。我无法想象如果不对其中的一些进行单元测试,可以编写多少代码。
  • 唯一不起作用的是 templatedoublylinkedlist.h 文件中的插入函数 我一路测试了其他所有内容,一切正常,甚至当我不调用该函数时它也可以工作插入。但是,当我在 main 中调用函数 insert 时,出现链接错误。
  • 我不同意这一点。甚至读取循环也错误地使用std::istream::eof() 作为条件并且未能测试所有包含的提取是否成功。如果您想知道为什么您的 last 记录被插入 两次,这就是原因。我原来的评论是成立的。 delete this; 后跟 this 的引用成员会调用清晰呈现的未定义行为

标签: c++ list sorting vector insert


【解决方案1】:

很简单,复制构造函数没有在 DoubleLinkedList 中定义主体。通常这样做是为了防止它被使用。正如您在下面看到的,复制构造函数没有主体,这就是链接器找不到它的原因。

DoublyLinkedList<T>(const DoublyLinkedList<T>& dll); // copy constructor

您需要复制构造函数的原因是向量模板使用它。您可以通过存储指向 DoubleLinkedList 而不是对象的指针来防止这种情况发生。

vector<DoublyLinkedList<Record>*> phoneBook(26);
for(char c='a' ; c<='z'; c++) 
{
    phoneBook[c] = new DoubleLinkedList();
}

【讨论】:

  • 没有定义是什么意思?我在我的班级中声明了它,然后它是在我的班级之外定义的第一个函数。我应该怎么做才能解决它?
  • 好的,它已经定义但没有实现。它没有实体。
猜你喜欢
  • 1970-01-01
  • 2018-12-25
  • 2018-11-04
  • 1970-01-01
  • 1970-01-01
  • 2011-04-13
  • 2017-09-23
  • 2022-06-17
  • 2023-04-07
相关资源
最近更新 更多